home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / pmode / pmode30b / pmode.asm < prev    next >
Assembly Source File  |  1994-05-30  |  139KB  |  3,186 lines

  1. ; PMODE v3.0 DPMI/VCPI/XMS/raw protected mode interface kernel.
  2. ; Copyright (c) 1994, Tran (a.k.a. Thomas Pytel).
  3.  
  4. public  _pm_selectors, _pm_pagetables, _pm_rmstacklen, _pm_rmstacks
  5. public  _pm_callbacks, _pm_pmstacklen, _pm_pmstacks
  6. public  _pm_info, _pm_init
  7.  
  8. .386p
  9. locals
  10. PMODE_TEXT      segment para public use16 'CODE'
  11. assume  cs:PMODE_TEXT, ds:PMODE_TEXT
  12.  
  13. off             equ     offset
  14.  
  15. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  16. ; DATA
  17. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  18. SELCODE         = 08h                   ; PMODE_TEXT code selector
  19. SELZERO         = 10h                   ; selector of entire memory space
  20. SELCALLBACKDS   = 18h                   ; callback DS selector
  21. SELREAL         = 20h                   ; real mode attributes selector
  22. SELVCPITSS      = 28h                   ; TSS selector for VCPI
  23. SELVCPICODE     = 30h                   ; VCPI call code selector
  24. SYSSELECTORS    = 9                     ; number of system selectors in GDT
  25.  
  26. align 4
  27. dpmiepmode      dd      ?               ; DPMI enter pmode addx
  28. codebase        dd      ?               ; PMODE_TEXT linear address
  29. vcpistrucaddx   dd      off vcpi_cr3    ; VCPI switch structure linear address
  30. oldint15vector  dd      ?               ; preserved INT 15h vector
  31.  
  32. pmstacktop    dd    ?        ; top of protected mode stack area
  33. pmstackbase    dd    ?        ; bottom of protected mode stack area
  34. callbackbase    dd      ?               ; base of real mode callbacks
  35. callbackseg     dw      ?               ; segment of callbacks
  36.  
  37. selzero         dw      SELZERO         ; for immediate segreg loading
  38. selcallbackds   dw      SELCALLBACKDS   ; for immediate segreg loading
  39.  
  40. rawextmemused   dw      1               ; raw extended memory used in K
  41. rawextmembase   dd      0ffffffffh      ; raw extended memory base
  42. rawextmemtop    dd      0               ; raw extended memory top
  43.  
  44. rmstackbase     dw      ?               ; bottom of real mode stack area
  45. rmstacktop      dw      ?               ; top of real mode stack area
  46. rmstackparmlen  dw      ?               ; for functions 0300h, 0301h, 0302h
  47.  
  48. gdtseg          dw      ?               ; segment of GDT
  49.  
  50. gdtlimit        dw      ?               ; GDT limit                          |
  51. gdtbase         dd      ?               ; GDT base                           |
  52. idtlimit        dw      7ffh            ; IDT limit                         |
  53. idtbase         dd      ?               ; IDT base                          |
  54. rmidtlimit      dw      3ffh            ; real mode IDT limit                |
  55. rmidtbase       dd      0               ; real mode IDT base                 |
  56.  
  57. rmtopmswrout    dw      off v_rmtopmsw  ; addx of real to protected routine
  58. pmtormswrout    dd      off v_pmtormsw  ; addx of protected to real routine
  59.  
  60. pagetablebase   dd      ?               ; base of page table area
  61. pagetabletop    dd      ?               ; top of page table area
  62. pagetablenum    db      ?               ; number of page tables
  63.  
  64. _pm_pagetables  db      1               ; number of page tables under VCPI
  65. _pm_selectors   dw      64              ; max selectors under VCPI/XMS/raw
  66. _pm_rmstacklen  dw      20h             ; real mode stack length, in para
  67. _pm_pmstacklen  dw      40h             ; protected mode stack length, in para
  68. _pm_rmstacks    db      4               ; real mode stack nesting
  69. _pm_pmstacks    db      2               ; protected mode stack nesting
  70. _pm_callbacks   db      16              ; number of real mode callbacks
  71.                 db      ?               ; for alignment
  72.  
  73. pmstacklen      dd      ?               ; protected mode stack length in bytes
  74.  
  75. processortype   db      ?               ; processor type                     |
  76. pmodetype       db      2               ; protected mode type                |
  77. picslave        db      70h             ; PIC slave base interrupt          |
  78. picmaster       db      8               ; PIC master base interrupt         |
  79.  
  80. tempd0          label   dword           ; temporary variables                |
  81. tempw0          label   word            ;                                    |
  82. tempb0          db      ?               ;                                    |
  83. tempb1          db      ?               ;                                    |
  84. tempw1          label   word            ;                                    |
  85. tempb2          db      ?               ;                                    |
  86. tempb3          db      ?               ;                                    |
  87. tempd1          label   dword           ;                                    |
  88. tempw2          label   word            ;                                    |
  89. tempb4          db      ?               ;                                    |
  90. tempb5          db      ?               ;                                    |
  91. tempw3          label   word            ;                                    |
  92. tempb6          db      ?               ;                                    |
  93. tempb7          db      ?               ;                                    |
  94.  
  95. xms_callip      dw      ?               ; XMS driver offset                 |
  96. xms_callcs      dw      ?               ; XMS driver segment                |
  97.  
  98. vcpi_cr3        dd      ?               ; VCPI CR3 value for protected mode |
  99. vcpi_gdtaddx    dd      off gdtlimit    ; linear addx of GDT limit and base |
  100. vcpi_idtaddx    dd      off idtlimit    ; linear addx of IDT limit and base |
  101. vcpi_selldt     dw      0               ; LDT selector for protected mode   |
  102. vcpi_seltss     dw      SELVCPITSS      ; TSS selector for protected mode   |
  103. vcpi_eip        dd      off v_rmtopmswpm; destination EIP in protected mode |
  104. vcpi_cs         dw      SELCODE         ; destination CS in protected mode  |
  105.  
  106. vcpi_calleip    dd      ?               ; VCPI protected mode call offset    |
  107. vcpi_callcs     dw      SELVCPICODE     ; VCPI protected mode call selector  |
  108.  
  109. initrouttbl     dw      r_init, x_init, v_init, d_init
  110.  
  111. int31functbl    dw      0900h, 0901h, 0902h, 0000h, 0001h, 0003h, 0006h, 0007h
  112.                 dw      0008h, 0009h, 0200h, 0201h, 0204h, 0205h, 0305h, 0306h
  113.                 dw      0400h
  114.                 dw      000ah, 000bh, 000ch, 000eh, 000fh
  115.                 dw      0300h, 0301h, 0302h
  116.                 dw      0303h, 0304h
  117.                 dw      0500h, 0501h, 0502h, 0503h, 050ah
  118. INT31FUNCNUM    = ($ - int31functbl) / 2
  119.  
  120. int31routtbl    dw      int310900, int310901, int310902, int310000
  121.                 dw      int310001, int310003, int310006, int310007
  122.                 dw      int310008, int310009, int310200, int310201
  123.                 dw      int310204, int310205, int310305, int310306
  124.                 dw      int310400
  125.                 dw      int31000a, int31000b, int31000c, int31000e, int31000f
  126.                 dw      int310300, int310301, int310302
  127.                 dw      int310303, int310304
  128. int31mrouttbl   dw      int310500v, int310501v, int310502v, int310503v
  129.                 dw      int31050av
  130. int31mxrouttbl  dw      int310500x, int310501x, int310502x, int310503x
  131.                 dw      int31050ax
  132. int31mrrouttbl  dw      int310500r, int310501r, int310502r, int310503r
  133.                 dw      int31050ar
  134. int31mnrouttbl  dw      int310500rnomem, int31fail8013, int31fail8023
  135.                 dw      int31fail8023, int31fail8023
  136.  
  137. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  138. ; DETECT/INIT CODE
  139. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  140.  
  141. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  142. ; Get protected mode info
  143. ; Out:
  144. ;   AX - return code:
  145. ;     0000h - successful
  146. ;     0001h - no 80386+ detected
  147. ;     0002h - system already in protected mode and no VCPI or DPMI found
  148. ;     0003h - DPMI - host is not 32bit
  149. ;   CF - set on error, if no error:
  150. ;     BX - number of paragraphs needed for protected mode data (may be 0)
  151. ;     CL - processor type:
  152. ;       03h - 80386
  153. ;       04h - 80486
  154. ;       05h - 80586
  155. ;       06h-FFh - reserved for future use
  156. ;     CH - protected mode type:
  157. ;       00h - raw
  158. ;       01h - XMS
  159. ;       02h - VCPI
  160. ;       03h - DPMI
  161. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  162. _pm_info:
  163.         push dx si di ds es bx cx       ; preserve registers
  164.  
  165.         push cs                         ; DS = CS (PMODE_TEXT)
  166.         pop ds
  167.  
  168.         mov ax,1687h                    ; check for DPMI
  169.         int 2fh
  170.  
  171.         or ax,ax                        ; DPMI present?
  172.         jnz short @@infof0              ; if no, go on
  173.  
  174.         mov ax,3                        ; error code in case DPMI not 32bit
  175.         test bl,1                       ; is DPMI 32bit?
  176.         jz @@infofail                   ; if no, fail
  177.  
  178.         mov ax,1                        ; error code in case no processor 386+
  179.         cmp cl,3                        ; is processor 386+?
  180.         jb @@infofail                   ; if no, fail
  181.  
  182.         mov word ptr dpmiepmode[0],di   ; store DPMI initial mode switch addx
  183.         mov word ptr dpmiepmode[2],es
  184.  
  185.         mov bx,si                       ; BX = number of paragraphs needed
  186.         mov ch,3                        ; pmode type is 3 (DPMI)
  187.  
  188.         jmp @@infook                    ; go to done ok
  189.  
  190. ;-----------------------------------------------------------------------------
  191. @@infof0:
  192.         call detect_processor           ; get processor type
  193.  
  194.         mov ax,1                        ; error code in case no processor 386+
  195.         cmp cl,3                        ; is processor 386+?
  196.         jb @@infofail                   ; if no, fail
  197.  
  198.         mov processortype,cl            ; store processor type
  199.  
  200. ;-----------------------------------------------------------------------------
  201.         xor ax,ax                       ; get INT 67h vector
  202.         mov es,ax
  203.         mov ax,es:[67h*4]
  204.         or ax,es:[67h*4+2]              ; is vector NULL
  205.         jz short @@infof2               ; if yes, no VCPI
  206.  
  207.         mov ax,0de00h                   ; call VCPI installation check
  208.         int 67h
  209.         or ah,ah                        ; AH returned as 0?
  210.         jnz short @@infof2              ; if no, no VCPI
  211.  
  212.         movzx bx,_pm_pagetables         ; BX = VCPI page table memory needed
  213.         shl bx,8                        ; 100h paragraphs per page table
  214.         add bx,100h+0ffh+7+80h          ; + page dir + align buf + TSS + IDT
  215.  
  216.         mov ch,2                        ; pmode type is 2 (VCPI)
  217.  
  218.         jmp short @@infof1              ; go to figure other memory needed
  219.  
  220. ;-----------------------------------------------------------------------------
  221. @@infof2:
  222.         smsw ax                         ; AX = machine status word
  223.         test al,1                       ; is system in protected mode?
  224.         mov ax,2                        ; error code in case protected mode
  225.         jnz short @@infofail            ; if in protected mode, fail
  226.  
  227.         mov ax,4300h                    ; chek for XMS
  228.         int 2fh
  229.         cmp al,80h                      ; XMS present?
  230.         sete ch                         ; if yes, pmode type is XMS
  231.  
  232.         mov bx,80h                      ; BX = memory requirement (IDT)
  233.  
  234. ;-----------------------------------------------------------------------------
  235. @@infof1:
  236.         movzx ax,_pm_rmstacks           ; size of real mode stack area
  237.         imul ax,_pm_rmstacklen
  238.         add bx,ax
  239.  
  240.         movzx ax,_pm_pmstacks           ; size of protected mode stack area
  241.         imul ax,_pm_pmstacklen
  242.         add bx,ax
  243.  
  244.         movzx ax,_pm_callbacks          ; size of callbacks
  245.         imul ax,25
  246.         add ax,0fh
  247.         shr ax,4
  248.         add bx,ax
  249.  
  250.         mov ax,_pm_selectors            ; size of GDT
  251.         add ax,1+SYSSELECTORS+5
  252.         shr ax,1
  253.         add bx,ax
  254.  
  255.         jmp short @@infook              ; go to done ok
  256.  
  257. ;-----------------------------------------------------------------------------
  258. @@infofail:
  259.         pop cx bx                       ; restore BX and CX
  260.         stc                             ; carry set, failed
  261.         jmp short @@infodone
  262.  
  263. ;-----------------------------------------------------------------------------
  264. @@infook:
  265.         mov pmodetype,ch                ; store pmode type
  266.  
  267.         add sp,4                        ; skip BX and CX on stack
  268.         xor ax,ax                       ; success code, also clear carry flag
  269.  
  270. ;-----------------------------------------------------------------------------
  271. @@infodone:
  272.         pop es ds di si dx              ; restore other registers
  273.         retf                            ; return
  274.  
  275. ;─────────────────────────────────────────────────────────────────────────────
  276. detect_processor:                       ; get processor: 386, 486, or 586
  277.         xor cl,cl                       ; processor type 0 in case of exit
  278.  
  279.         pushf                           ; transfer FLAGS to BX
  280.         pop bx
  281.  
  282.         mov ax,bx                       ; try to clear high 4 bits of FLAGS
  283.         and ah,0fh
  284.  
  285.         push ax                         ; transfer AX to FLAGS
  286.         popf
  287.         pushf                           ; transfer FLAGS back to AX
  288.         pop ax
  289.  
  290.         and ah,0f0h                     ; isolate high 4 bits
  291.         cmp ah,0f0h
  292.         je short @@detect_processordone ; if bits are set, CPU is 8086/8
  293.  
  294.         mov cl,2                        ; processor type 2 in case of exit
  295.  
  296.         or bh,0f0h                      ; try to set high 4 bits of FLAGS
  297.  
  298.         push bx                         ; transfer BX to FLAGS
  299.         popf
  300.         pushf                           ; transfer FLAGS to AX
  301.         pop ax
  302.  
  303.         and ah,0f0h                     ; isolate high 4 bits
  304.         jz short @@detect_processordone ; if bits are not set, CPU is 80286
  305.  
  306.         inc cx                          ; processor type 3 in case of exit
  307.  
  308.         push eax ebx                    ; preserve 32bit registers
  309.  
  310.         pushfd                          ; transfer EFLAGS to EBX
  311.         pop ebx
  312.  
  313.         mov eax,ebx                     ; try to flip AC bit in EFLAGS
  314.         xor eax,40000h
  315.  
  316.         push eax                        ; transfer EAX to EFLAGS
  317.         popfd
  318.         pushfd                          ; transfer EFLAGS back to EAX
  319.         pop eax
  320.  
  321.         xor eax,ebx                     ; AC bit fliped?
  322.         jz short @@detect_processordone2; if no, CPU is 386
  323.  
  324.         inc cx                          ; processor type 3 in case of exit
  325.  
  326.         mov eax,ebx                     ; try to flip ID bit in EFLAGS
  327.         xor eax,200000h
  328.  
  329.         push eax                        ; transfer EAX to EFLAGS
  330.         popfd
  331.         pushfd                          ; transfer EFLAGS back to EAX
  332.         pop eax
  333.  
  334.         xor eax,ebx                     ; ID bit fliped?
  335.         jz short @@detect_processordone2; if no, CPU is 486
  336.  
  337.         inc cx                          ; processor type 5, CPU is 586
  338.  
  339. @@detect_processordone2:
  340.         pop ebx eax                     ; restore 32bit registers
  341.  
  342. @@detect_processordone:
  343.         ret                             ; return
  344.  
  345. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  346. ; Initialize protected mode
  347. ; In:
  348. ;   ES - real mode segment for protected mode data (ignored if not needed)
  349. ; Out:
  350. ;   AX - return code:
  351. ;     0000h - successful
  352. ;     0001h - no 80386+ detected
  353. ;     0002h - system already in protected mode and no VCPI or DPMI found
  354. ;     0003h - DPMI - host is not 32bit
  355. ;     0004h - could not enable A20 gate
  356. ;     0005h - DPMI - could not enter 32bit protected mode
  357. ;     0006h - DPMI - could not allocate needed selectors
  358. ;   CF - set on error, if no error:
  359. ;     ESP - high word clear
  360. ;     CS - 16bit selector for real mode CS with limit of 64k
  361. ;     SS - selector for real mode SS with limit of 64k
  362. ;     DS - selector for real mode DS with limit of 64k
  363. ;     ES - selector for PSP with limit of 100h
  364. ;     FS - 0 (NULL selector)
  365. ;     GS - 0 (NULL selector)
  366. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  367. _pm_init:
  368.         push bx cx                      ; get initial info on protected mode
  369.         call far ptr _pm_info
  370.         pop cx bx
  371.         jnc short @@initf0              ; error?
  372.  
  373.         retf                            ; yup, abort
  374.  
  375. @@initf0:                               ; no error, init protected mode
  376.         pushad
  377.         push ds
  378.         mov bp,sp
  379.         push cs                         ; DS = PMODE_TEXT
  380.         pop ds
  381.         cld
  382.  
  383.         mov eax,PMODE_TEXT              ; set base addx of PMODE_TEXT
  384.         shl eax,4
  385.         mov codebase,eax
  386.  
  387.         movzx bx,pmodetype              ; jump to appropriate init code
  388.         shl bx,1
  389.         jmp initrouttbl[bx]
  390.  
  391. ;═════════════════════════════════════════════════════════════════════════════
  392. d_init:                                 ; DPMI protected mode init
  393.         pop ds                          ; get original caller DS from stack
  394.         mov ax,1                        ; enter DPMI protected mode
  395.         call cs:dpmiepmode
  396.         push ds                         ; put DS back onto stack
  397.         jnc short dvxr_init             ; error? if not, go on with init
  398.  
  399.         mov bx,6                        ; error entering protected mode, set
  400.         cmp ax,8011h                    ;  error code and abort
  401.         stc
  402.         je short init_done
  403.         mov bl,5                        ; error code 5, not 6
  404.  
  405. ;-----------------------------------------------------------------------------
  406. init_done:                              ; return with return code
  407.         mov [bp+30],bx
  408.         pop ds
  409.         popad
  410.         retf
  411.  
  412. ;─────────────────────────────────────────────────────────────────────────────
  413. dvxr_init:                              ; DPMI/VCPI/XMS/raw common init tail
  414.         mov bx,cs                       ; BX = CS if needed for same seg exit
  415.         cmp word ptr [bp+36],PMODE_TEXT ; call came from same segment?
  416.         je short @@dvxr_initdone        ; if yes, done now
  417.  
  418.         xor ax,ax                       ; allocate selector for return code
  419.         mov cx,1
  420.         int 31h
  421.         jnc short @@dvxr_initf0
  422.  
  423.         mov ah,4ch                      ; could not allocate selector
  424.         int 21h                         ; terminate immediately
  425.  
  426. @@dvxr_initf0:
  427.         mov bx,ax                       ; new code descriptor for return
  428.  
  429.         mov ax,0007h                    ; set base address of calling segment
  430.         xor cx,cx
  431.         mov dx,[bp+36]
  432.         shld cx,dx,4
  433.         shl dx,4
  434.         int 31h
  435.  
  436.         mov ax,0008h                    ; set selector limit of 64k
  437.         xor cx,cx
  438.         mov dx,0ffffh
  439.         int 31h
  440.  
  441.         mov ax,0009h                    ; set selector type and access rights
  442.         mov dx,cs                       ; get DPL from current CPL, and access
  443.         lar cx,dx                       ;  rights and type from current CS
  444.         shr cx,8                        ; type is already 16bit code segment
  445.         int 31h
  446.  
  447. @@dvxr_initdone:
  448.         mov [bp+36],bx                  ; store selector in return address
  449.         xor bx,bx                       ; init successful, carry clear
  450.         jmp init_done
  451.  
  452. ;═════════════════════════════════════════════════════════════════════════════
  453. v_init:                                 ; VCPI protected mode init
  454.         mov ax,0de0ah                   ; get PIC mappings
  455.         int 67h
  456.         mov picmaster,bl
  457.         mov picslave,cl
  458.  
  459.         mov eax,codebase                ; adjust addresses for VCPI structure
  460.         add vcpi_gdtaddx,eax
  461.         add vcpi_idtaddx,eax
  462.         add vcpistrucaddx,eax
  463.  
  464.         mov dx,es                       ; align data area on page
  465.         add dx,0ffh
  466.         xor dl,dl
  467.         mov es,dx
  468.  
  469.         movzx eax,dx                    ; set base and top of page table area
  470.         shl eax,4
  471.         add eax,1000h
  472.         mov pagetablebase,eax
  473.         movzx ecx,_pm_pagetables
  474.         shl ecx,12
  475.         add eax,ecx
  476.         mov pagetabletop,eax
  477.  
  478.         xor di,di                       ; clear page dir and first page table
  479.         mov cx,1000h
  480.         xor ax,ax
  481.         rep stosw
  482.  
  483.         mov gs,dx                       ; FS = segment of page directory
  484.         lea eax,[edx+100h]
  485.         mov es,ax                       ; ES = segment of first page table
  486.         mov fs,ax                       ; GS = segment of first page table
  487.  
  488.         push ss                         ; stack space for VCPI descriptors
  489.         pop ds
  490.         sub sp,8*3
  491.         mov si,sp
  492.  
  493.         xor di,di                       ; get VCPI protected mode interface
  494.         mov ax,0de01h
  495.         int 67h
  496.  
  497.         push cs                         ; DS = PMODE_TEXT
  498.         pop ds
  499.  
  500.         mov vcpi_calleip,ebx            ; store protected mode VCPI call EIP
  501.         movzx si,dh                     ; get physical address of page dir
  502.         shl si,2                        ;  from first page table for CR3
  503.         lods dword ptr fs:[si]
  504.         mov vcpi_cr3,eax
  505.  
  506. @@v_initl0:
  507.         and byte ptr es:[di+1],0f1h     ; clear bits 9-11 in copied page table
  508.         sub di,4
  509.         jnc @@v_initl0
  510.  
  511.         mov dx,es                       ; DX = current page table segment
  512.         xor ebx,ebx                     ; index in page dir, also loop counter
  513.         jmp short @@v_initl1f0
  514.  
  515. @@v_initl1:
  516.         xor di,di                       ; clear page table
  517.         mov cx,800h
  518.         xor ax,ax
  519.         rep stosw
  520.  
  521. @@v_initl1f0:
  522.         add dx,100h                     ; increment page table segment
  523.         mov es,dx
  524.  
  525.         lods dword ptr fs:[si]          ; set physical address of page table
  526.         mov gs:[ebx*4],eax              ;  in page directory
  527.  
  528.         inc bx                          ; increment index in page directory
  529.         cmp bl,_pm_pagetables           ; at end of page tables?
  530.         jb @@v_initl1                   ; if no, loop
  531.  
  532. ;-----------------------------------------------------------------------------
  533.         push dx                         ; preserve seg of TSS for later use
  534.  
  535.         xor di,di                       ; clear TSS with all 0
  536.         mov cx,34h
  537.         xor ax,ax
  538.         rep stosw
  539.  
  540.         mov eax,vcpi_cr3                ; set CR3 in TSS
  541.         mov es:[1ch],eax
  542.         mov dword ptr es:[66h],68h      ; set offset of I/O permission bitmap
  543.  
  544.         add dx,7                        ; increment next data area ptr
  545.         mov es,dx
  546.  
  547. ;─────────────────────────────────────────────────────────────────────────────
  548. vxr_init:                               ; VCPI/XMS/raw common init tail
  549.         mov ax,es                       ; set IDT base address
  550.         movzx ebx,ax
  551.         shl ebx,4
  552.         mov idtbase,ebx
  553.  
  554.         movzx bx,_pm_rmstacks           ; set top and base of real mode stack
  555.         imul bx,_pm_rmstacklen          ;  area for interrupt redirection
  556.         add ax,80h                      ;  from protected mode
  557.         mov rmstackbase,ax
  558.         add ax,bx
  559.         mov rmstacktop,ax
  560.  
  561.         xor di,di                       ; set up IDT
  562.         mov dx,word ptr picslave
  563.         xor ecx,ecx
  564.  
  565. @@vxr_initl0:
  566.         lea eax,[SELCODE*10000h+ecx*4+off intrmatrix]
  567.         stosd
  568.  
  569.         mov eax,8e00h                   ; interrupt gate type
  570.         mov bl,cl                       ; isolate high 5 bits of int num
  571.         and bl,0f8h
  572.  
  573.         test cl,0f8h                    ; one of the low 8 interrupts?
  574.         jz short @@vxr_initl0f0         ; if yes, store as interrupt gate
  575.  
  576.         cmp bl,dl                       ; one of the high IRQs?
  577.         je short @@vxr_initl0f0         ; if yes, store as interrupt gate
  578.         cmp bl,dh                       ; one of the low IRQs?
  579.         je short @@vxr_initl0f0         ; if yes, store as interrupt gate
  580.  
  581.         or ah,1                         ; set to trap gate type
  582.  
  583. @@vxr_initl0f0:
  584.         stosd
  585.  
  586.         inc cl                          ; increment interrupt number
  587.         jnz @@vxr_initl0                ; loop if more interrupts to go
  588.  
  589.         mov word ptr es:[8*31h],off int31    ; protected mode INT 31h
  590.         mov word ptr es:[8*21h],off int21    ; protected mode INT 21h
  591.  
  592.         mov es,rmstacktop               ; set next data area ptr to end of
  593.                                         ;  real mode stack area
  594. ;-----------------------------------------------------------------------------
  595.     mov ax,es            ; set protected mode stack area base
  596.         movzx eax,ax                    ;  for callbacks
  597.         shl eax,4
  598.     mov pmstackbase,eax
  599.  
  600.         movzx ecx,_pm_pmstacklen        ; set protected mode stack area top
  601.         movzx ebx,_pm_pmstacks          ;  for callbacks
  602.         shl ecx,4
  603.         mov pmstacklen,ecx              ; protected mode stack size in bytes
  604.         imul ebx,ecx
  605.         add ebx,eax
  606.         mov pmstacktop,ebx              ; protected mode stack area top
  607.  
  608.         mov cl,_pm_callbacks            ; CL = number of callbacks
  609.         or cl,cl                        ; any callbacks?
  610.         jz short @@vxr_initf3           ; if no, done with this part
  611.  
  612.         mov callbackbase,ebx            ; top of stacks is base of callbacks
  613.         shr ebx,4                       ; BX = seg of callback area
  614.         mov callbackseg,bx
  615.  
  616.         mov es,bx                       ; ES = seg of callback area
  617.         xor di,di                       ; location within callback seg
  618.  
  619. @@vxr_initl1:
  620.         mov word ptr es:[di],6066h      ; PUSHAD instruction
  621.         mov byte ptr es:[di+2],068h     ; PUSH WORD instruction
  622.         mov word ptr es:[di+3],0        ; immediate 0 used as free flag
  623.         mov word ptr es:[di+5],06866h   ; PUSH DWORD instruction
  624.         mov byte ptr es:[di+11],0b9h    ; MOV CX,? instruction
  625.         mov word ptr es:[di+14],06866h  ; PUSH DWORD instruction
  626.         mov byte ptr es:[di+20],0eah    ; JMP FAR PTR ?:? intruction
  627.         mov word ptr es:[di+21],off callback
  628.         mov word ptr es:[di+23],PMODE_TEXT
  629.  
  630.         add di,25                       ; increment ptr to callback
  631.         dec cl                          ; decrement loop counter
  632.         jnz @@vxr_initl1                ; if more callbacks to do, loop
  633.  
  634.     add di,0fh            ; align next data area on paragraph
  635.     shr di,4
  636.     add bx,di
  637.         mov es,bx                       ; set ES to base of next data area
  638.  
  639. @@vxr_initf3:
  640.  
  641. ;-----------------------------------------------------------------------------
  642.     mov gdtseg,es            ; store segment of GDT
  643.  
  644.         mov ax,es                       ; set GDT base address
  645.         movzx eax,ax
  646.         shl eax,4
  647.         mov gdtbase,eax
  648.  
  649.         mov cx,_pm_selectors            ; set GDT limit
  650.         lea ecx,[8*ecx+8*5+8*SYSSELECTORS-1]
  651.         mov gdtlimit,cx
  652.  
  653.         xor di,di                       ; clear GDT with all 0
  654.         inc cx
  655.         shr cx,1
  656.         xor ax,ax
  657.         rep stosw
  658.  
  659.         cmp pmodetype,2                 ; if under VCPI, do VCPI GDT set up
  660.         jne short @@vxr_initf1
  661.  
  662.         pop ax                          ; restore TSS seg from stack
  663.         movzx eax,ax                    ; set up TSS selector in GDT
  664.         shl eax,4
  665.         mov dword ptr es:[SELVCPITSS+2],eax
  666.         mov byte ptr es:[SELVCPITSS],67h
  667.         mov byte ptr es:[SELVCPITSS+5],89h
  668.  
  669.         mov di,SELVCPICODE              ; copy 3 VCPI descriptors from stack
  670.         mov si,sp                       ;  to GDT
  671.         mov cx,4*3
  672.         rep movs word ptr es:[di],word ptr ss:[si]
  673.  
  674.         add sp,8*3                      ; adjust stack
  675.  
  676. @@vxr_initf1:
  677.         mov word ptr es:[SELZERO],0ffffh; set SELZERO descriptor
  678.         mov word ptr es:[SELZERO+5],0df92h
  679.  
  680.         mov word ptr es:[SELCALLBACKDS],0ffffh  ; set callback DS descriptor
  681.     mov word ptr es:[SELCALLBACKDS+5],0df92h
  682.  
  683.         mov word ptr es:[SELREAL],0ffffh; set real mode attributes descriptor
  684.         mov word ptr es:[SELREAL+5],01092h
  685.  
  686.         mov ax,cs                       ; set SELCODE descriptor (PMODE_TEXT)
  687.         mov bx,SELCODE                  ; BX = index to SELCODE descriptor
  688.         mov cx,0ffffh                   ; CX = limit (64k)
  689.         mov dx,109ah                    ; DX = access rights
  690.         call vxr_initsetdsc
  691.  
  692.         mov bx,8*SYSSELECTORS           ; BX = base of free descriptors
  693.         push bx                         ; store selector
  694.  
  695.         mov ax,ss                       ; set caller SS descriptor
  696.         mov dx,5092h
  697.         call vxr_initsetdsc
  698.  
  699.         mov ax,[bp]                     ; set caller DS descriptor
  700.         mov [bp],bx                     ; put DS selector on stack for exit
  701.         call vxr_initsetdsc
  702.  
  703.         push bx                         ; get PSP segment
  704.         mov ah,51h
  705.         int 21h
  706.         mov si,bx
  707.         pop bx
  708.  
  709.         mov fs,si                       ; set caller environment descriptor
  710.         mov ax,fs:[2ch]
  711.         or ax,ax                        ; is environment seg 0?
  712.         jz short @@vxr_initf0           ; if yes, dont convert to descriptor
  713.         mov fs:[2ch],bx                 ; store selector value in PSP
  714.         call vxr_initsetdsc
  715.  
  716. @@vxr_initf0:
  717.         mov ax,si                       ; set caller PSP descriptor
  718.         mov cx,0ffh                     ; limit is 100h bytes
  719.         call vxr_initsetdsc
  720.  
  721. ;-----------------------------------------------------------------------------
  722.         lea ecx,[ebx-8]                 ; CX = ES descriptor, just set
  723.         pop dx                          ; DX = SS descriptor, from stack
  724.         mov ax,SELZERO                  ; AX = DS descriptor, SELZERO
  725.         movzx ebx,sp                    ; EBX = SP, current SP - same stack
  726.         mov si,SELCODE                  ; target CS is SELCODE, same segment
  727.         mov edi,off @@vxr_initf2        ; target EIP
  728.  
  729.         jmp rmtopmswrout                ; jump to mode switch routine
  730.  
  731. @@vxr_initf2:   
  732.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  733.         mov eax,ds:[4*15h]              ; get INT 15h vector
  734.         mov ds:oldint15vector[edi],eax  ; store INT 15h vector
  735.  
  736.         mov esi,cs:rawextmembase        ; ESI = raw base of extended memory
  737.         cmp esi,cs:rawextmemtop         ; is there any raw extended memory?
  738.         jae dvxr_init                   ; if no, go DPMI/VCPI/XMS/raw init
  739.  
  740.         dw 0b866h,off int15,PMODE_TEXT  ; MOV EAX,PMODE_TEXT:offset int15
  741.         mov ds:[4*15h],eax              ; set new INT 15h handler
  742.  
  743.         mov edi,cs:rawextmemtop         ; EDI = raw top of extended memory
  744.         mov eax,edi                     ; EAX = size of extended memory
  745.         sub eax,esi
  746.         sub eax,10h                     ; subtract memory control block size
  747.         mov [edi-16],eax                ; store size in memory control block
  748.         xor eax,eax
  749.         mov [edi-12],eax                ; no next memory control block
  750.         mov [edi-8],eax                 ; no previous memory control block
  751.         mov [edi-4],al                  ; memory block is free
  752.  
  753.         jmp dvxr_init                   ; go to DPMI/VCPI/XMS/raw init tail
  754.  
  755. ;─────────────────────────────────────────────────────────────────────────────
  756. vxr_initsetdsc:                         ; set descriptor for VCPI/XMS/raw init
  757.         movzx eax,ax                    ; EAX = base of segment
  758.         shl eax,4
  759.         mov word ptr es:[bx],cx         ; limit = CX
  760.         mov dword ptr es:[bx+2],eax     ; base address = EAX
  761.         mov word ptr es:[bx+5],dx       ; access rights = DX
  762.         add bx,8                        ; increment descriptor index
  763.         ret
  764.  
  765. ;═════════════════════════════════════════════════════════════════════════════
  766. x_init:                                 ; XMS protected mode init
  767.         push es                         ; preserve ES, INT 2Fh destroys it
  768.  
  769.         mov ax,4310h                    ; get XMS driver address
  770.         int 2fh
  771.  
  772.         mov xms_callip,bx               ; store XMS driver address
  773.         mov xms_callcs,es
  774.  
  775.         pop es                          ; restore ES (buffer segment)
  776.  
  777.         mov ah,3                        ; enable A20
  778.         call dword ptr xms_callip
  779.  
  780.         mov bx,4                        ; error code 0004h in case of error
  781.         cmp ax,1                        ; error enabling A20?
  782.         jc init_done                    ; if yes, exit with error 0004h
  783.  
  784.         mov si,off int31mxrouttbl       ; set XMS memory allocation functions
  785.  
  786. ;─────────────────────────────────────────────────────────────────────────────
  787. xr_init:                                ; XMS/raw common init tail
  788.         push es                         ; preserve ES, INT 2Fh destroys it
  789.  
  790.         push ds                         ; ES = DS for table copy
  791.         pop es
  792.  
  793.         mov di,off int31mrouttbl        ; copy memory allocation function
  794.         mov cx,5                        ;  addresses to table
  795.         rep movsw
  796.  
  797.         pop es                          ; restore ES (buffer segment)
  798.  
  799.         mov rmtopmswrout,off xr_rmtopmsw; set XMS/raw mode switch addresses
  800.         mov pmtormswrout,off xr_pmtormsw
  801.  
  802.         jmp vxr_init                    ; go to VCPI/XMS/raw continue init
  803.  
  804. ;═════════════════════════════════════════════════════════════════════════════
  805. r_init:                                 ; raw protected mode init
  806.         mov ah,88h                      ; how much extended memory free
  807.         int 15h
  808.  
  809.         mov si,off int31mnrouttbl       ; SI -> no memory allocation functions
  810.         or ax,ax                        ; if none, done with raw init
  811.         jz xr_init
  812.  
  813.         movzx eax,ax                    ; convert AX K to ptr to top of mem
  814.         shl eax,10
  815.         add eax,100000h
  816.         mov cs:rawextmemtop,eax
  817.  
  818.         call enablea20                  ; enable A20
  819.  
  820.         push es                         ; preserve ES (buffer segment)
  821.  
  822.         xor cx,cx                       ; ES -> 0 (interrupt vector table)
  823.         mov es,cx
  824.         les bx,dword ptr es:[4*19h]     ; ES:BX -> int vector table
  825.  
  826.         mov eax,100000h                 ; initial free extended memory base
  827.         cmp dword ptr es:[bx+12h],'SIDV'; VDISK memory allocation?
  828.         jne short @@r_initf0            ; if present, get base of free mem
  829.  
  830.         mov eax,dword ptr es:[bx+2ch]   ; get first free byte of extended mem
  831.         add eax,0fh                     ; align on paragraph
  832.         and eax,0fffff0h                ; address is only 24bit
  833.  
  834. @@r_initf0:
  835.         dec cx                          ; ES -> 0ffffh for ext mem addressing
  836.         mov es,cx
  837.  
  838.         cmp dword ptr es:[13h],'SIDV'   ; VDISK memory allocation?
  839.         jne short @@r_initf1            ; if present, get base of free mem
  840.  
  841.         movzx ebx,word ptr es:[2eh]     ; get first free K of extended memory
  842.         shl ebx,10                      ; adjust K to bytes
  843.  
  844.         cmp eax,ebx                     ; pick larger of 2 addresses
  845.         ja short @@r_initf1
  846.  
  847.         mov eax,ebx
  848.  
  849. @@r_initf1:
  850.         pop es                          ; restore ES (buffer segment)
  851.  
  852.         mov si,off int31mnrouttbl       ; SI -> no memory allocation functions
  853.         cmp eax,cs:rawextmemtop         ; any valid free extended memory
  854.         jae xr_init                     ; if none, done with raw init
  855.  
  856.         mov cs:rawextmembase,eax
  857.         mov si,off int31mrrouttbl       ; set raw memory allocation functions
  858.  
  859.         jmp xr_init                     ; go to XMS/raw continue init
  860.  
  861. ;─────────────────────────────────────────────────────────────────────────────
  862. enablea20:                              ; hardware enable gate A20
  863.         pushf
  864.         push fs gs
  865.         cli
  866.  
  867.         xor ax,ax                       ; set A20 test segments 0 and 0ffffh
  868.         mov fs,ax
  869.         dec ax
  870.         mov gs,ax
  871.  
  872.         call enablea20test              ; is A20 already enabled?
  873.         jz short @@enablea20done        ; if yes, done
  874.  
  875.         in al,92h                       ; PS/2 A20 enable
  876.         or al,2
  877.         jmp short $+2
  878.         jmp short $+2
  879.         jmp short $+2
  880.         out 92h,al
  881.  
  882.         call enablea20test              ; is A20 enabled?
  883.         jz short @@enablea20done        ; if yes, done
  884.  
  885.         call enablea20kbwait            ; AT A20 enable
  886.         jnz short @@enablea20f0
  887.  
  888.         mov al,0d1h
  889.         out 64h,al
  890.  
  891.         call enablea20kbwait
  892.         jnz short @@enablea20f0
  893.  
  894.         mov al,0dfh
  895.         out 60h,al
  896.  
  897.         call enablea20kbwait
  898.  
  899. @@enablea20f0:                          ; wait for A20 to enable
  900.         mov cx,800h                     ; do 800h tries
  901.  
  902. @@enablea20l0:
  903.         call enablea20test              ; is A20 enabled?
  904.         jz @@enablea20done              ; if yes, done
  905.  
  906.         in al,40h                       ; get current tick counter
  907.         jmp short $+2
  908.         jmp short $+2
  909.         jmp short $+2
  910.         in al,40h
  911.         mov ah,al
  912.  
  913. @@enablea20l1:                          ; wait a single tick
  914.         in al,40h
  915.         jmp short $+2
  916.         jmp short $+2
  917.         jmp short $+2
  918.         in al,40h
  919.         cmp al,ah
  920.         je @@enablea20l1
  921.  
  922.         loop @@enablea20l0              ; loop for another try
  923.  
  924.         mov bp,sp                       ; error, A20 did not enable
  925.         mov ax,4                        ; error code 4
  926.         mov word ptr [bp+6],off init_done       ; set init_done return address
  927.  
  928. @@enablea20done:
  929.         pop gs fs
  930.         popf
  931.         ret
  932.  
  933. ;-----------------------------------------------------------------------------
  934. enablea20kbwait:                        ; wait for safe to write to 8042
  935.         xor cx,cx
  936. @@enablea20kbwaitl0:
  937.         jmp short $+2
  938.         jmp short $+2
  939.         jmp short $+2
  940.         in al,64h                       ; read 8042 status
  941.         test al,2                       ; buffer full?
  942.         loopnz @@enablea20kbwaitl0      ; if yes, loop
  943.         ret
  944.  
  945. ;-----------------------------------------------------------------------------
  946. enablea20test:                          ; test for enabled A20
  947.         mov al,fs:[0]                   ; get byte from 0:0
  948.         mov ah,al                       ; preserve old byte
  949.         not al                          ; modify byte
  950.         xchg al,gs:[10h]                ; put modified byte to 0ffffh:10h
  951.         cmp ah,fs:[0]                   ; set zero if byte at 0:0 not modified
  952.         xchg al,gs:[10h]                ; put back old byte at 0ffffh:10h
  953.         ret                             ; return, zero if A20 enabled
  954.  
  955. ;═════════════════════════════════════════════════════════════════════════════
  956. int15:                                  ; real mode INT 15h handler
  957.         cmp ah,88h                      ; function 88h?
  958.         je short @@int15f0              ; if yes, need to process
  959.  
  960.         jmp cs:oldint15vector           ; no, go on to old INT 15h handler
  961.  
  962. @@int15f0:
  963.         pushf                           ; call old int 15h handler
  964.         call cs:oldint15vector
  965.  
  966.         sub ax,cs:rawextmemused         ; adjust AX by extended memory used
  967.  
  968.         iret                            ; return with new AX extended memory
  969.  
  970. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  971. ; PROTECTED MODE KERNEL CODE
  972. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  973.  
  974. ;═════════════════════════════════════════════════════════════════════════════
  975. v_rmtopmsw:                             ; VCPI real to protected switch
  976.         pushf                           ; store FLAGS
  977.         cli
  978.         push cs                         ; DS = PMODE_TEXT
  979.         pop ds
  980.         pop tempw0                      ; move FLAGS from stack to temp
  981.         mov tempw1,ax                   ; store AX (protected mode DS)
  982.         mov tempw2,si                   ; store SI (protected mode CS)
  983.         mov esi,vcpistrucaddx           ; ESI = linear addx of VCPI structure
  984.         mov ax,0de0ch                   ; VCPI switch to protected mode
  985.         int 67h
  986. v_rmtopmswpm:
  987.         mov ss,dx                       ; load protected mode SS:ESP
  988.         mov esp,ebx
  989.         mov ds,cs:tempw1                ; load protected mode DS
  990.         mov es,cx                       ; load protected mode ES
  991.         xor ax,ax
  992.         mov fs,ax                       ; load protected mode FS with NULL
  993.         mov gs,ax                       ; load protected mode GS with NULL
  994.         pushfd                          ; store EFLAGS
  995.         mov ax,cs:tempw0                ; move bits 0-11 of old FLAGS onto
  996.         and ah,0fh                      ;  stack for IRETD
  997.         and word ptr [esp],0f000h
  998.         or [esp],ax
  999.         push cs:tempd1                  ; store protected mode target CS
  1000.         push edi                        ; store protected mode target EIP
  1001.         iretd                           ; go to targed addx in protected mode
  1002.  
  1003. ;═════════════════════════════════════════════════════════════════════════════
  1004. v_pmtormsw:                             ; VCPI protected to real switch
  1005.         pushf                           ; store FLAGS
  1006.         cli
  1007.         push ax                         ; store AX (real mode DS)
  1008.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1009.         movzx ebx,bx                    ; clear high word of EBX, real mode SP
  1010.         movzx edx,dx                    ; clear high word of EDX, real mode SS
  1011.         lea eax,[edx*4]                 ; EAX = linear ptr to top of real mode
  1012.         lea eax,[eax*4+ebx]             ;  stack
  1013.         mov dword ptr ds:[eax-4],0      ; store real mode GS
  1014.         mov dword ptr ds:[eax-8],0      ; store real mode FS
  1015.         movzx ecx,cx                    ; clear high word of ECX, real mode ES
  1016.         mov ds:[eax-16],ecx             ; store real mode ES
  1017.         pop cx                          ; move real mode DS from protected
  1018.         mov ds:[eax-12],ecx             ;  mode stack to VCPI call stack
  1019.         mov ds:[eax-20],edx             ; store real mode SS
  1020.         mov ds:[eax-24],ebx             ; store real mode SP
  1021.         mov dword ptr ds:[eax-32],PMODE_TEXT            ; store real mode CS
  1022.     mov dword ptr ds:[eax-36],off @@v_pmtormswf0    ; store real mode IP
  1023.         pop bx                          ; restore FLAGS from stack
  1024.         mov ss,cs:selzero               ; SS -> 0 (beginning of memory)
  1025.         lea esp,[eax-4*9]               ; ESP = stack ptr for VCPI call
  1026.         mov ax,0de0ch                   ; VCPI switch to real mode (V86)
  1027.     call fword ptr cs:vcpi_calleip
  1028. @@v_pmtormswf0:
  1029.         push bx                         ; store old FLAGS
  1030.     push si             ; store target CS in real mode
  1031.     push di             ; store target IP in real mode
  1032.     iret                ; go to target addx in real mode
  1033.  
  1034. ;═════════════════════════════════════════════════════════════════════════════
  1035. xr_rmtopmsw:                            ; XMS/raw real to protected switch
  1036.         pushfd                          ; store EFLAGS
  1037.         cli
  1038.         pop cs:tempd0                   ; move EFLAGS from stack to temp
  1039.         mov cs:tempw2,ax                ; store AX (protected mode DS)
  1040.         lidt fword ptr cs:idtlimit      ; load protected mode IDT
  1041.         lgdt fword ptr cs:gdtlimit      ; load protected mode GDT
  1042.         mov eax,cr0                     ; switch to protected mode
  1043.         or al,1
  1044.         mov cr0,eax
  1045.         db 0eah                         ; JMP FAR PTR SELCODE:$+4
  1046.         dw $+4,SELCODE                  ;  (clear prefetch que)
  1047.         mov ss,dx                       ; load protected mode SS:ESP
  1048.         mov esp,ebx
  1049.         mov ds,cs:tempw2                ; load protected mode DS
  1050.         mov es,cx                       ; load protected mode ES
  1051.         xor ax,ax
  1052.         mov fs,ax                       ; load protected mode FS with NULL
  1053.         mov gs,ax                       ; load protected mode GS with NULL
  1054.         pushf                           ; set NT=0 in current EFLAGS
  1055.         and byte ptr [esp+1],0bfh
  1056.         popf
  1057.         push cs:tempd0                  ; store old EFLAGS
  1058.         and byte ptr [esp+1],0bfh       ; set NT=0 in old EFLAGS
  1059.         push esi                        ; store protected mode target CS
  1060.         push edi                        ; store protected mode target EIP
  1061.         iretd                           ; go to targed addx in protected mode
  1062.  
  1063. ;═════════════════════════════════════════════════════════════════════════════
  1064. xr_pmtormsw:                            ; XMS/raw protected to real switch
  1065.         pushf                           ; store FLAGS
  1066.         cli
  1067.         push ax                         ; store AX (real mode DS)
  1068.         push cx                         ; store CX (real mode ES)
  1069.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1070.         mov ecx,cs:codebase             ; get offset of PMODE_TEXT from 0
  1071.         pop ds:tempw0[ecx]              ; move real mode ES from stack to temp
  1072.         pop ds:tempw1[ecx]              ; move real mode DS from stack to temp
  1073.         pop ds:tempw2[ecx]              ; move FLAGS from stack to temp
  1074.         mov ax,SELREAL                  ; load descriptors with real mode seg
  1075.         mov ds,ax                       ;  attributes
  1076.         mov es,ax
  1077.         mov fs,ax
  1078.         mov gs,ax
  1079.         mov ss,ax                       ; load descriptor with real mode attr
  1080.         movzx esp,bx                    ; load real mode SP, high word 0
  1081.         lidt fword ptr cs:rmidtlimit    ; load real mode IDT
  1082.         mov eax,cr0                     ; switch to real mode
  1083.         and al,0feh
  1084.         mov cr0,eax
  1085.         db 0eah                         ; JMP FAR PTR PMODE_TEXT:$+4
  1086.         dw $+4,PMODE_TEXT               ;  (clear prefetch que)
  1087.         mov ss,dx                       ; load real mode SS
  1088.         mov ds,cs:tempw1                ; load real mode DS
  1089.         mov es,cs:tempw0                ; load real mode ES
  1090.         xor ax,ax
  1091.         mov fs,ax                       ; load real mode FS with NULL
  1092.         mov gs,ax                       ; load real mode GS with NULL
  1093.         push cs:tempw2                  ; store old FLAGS
  1094.         push si                         ; store real mode target CS
  1095.         push di                         ; store real mode target IP
  1096.         iret                            ; go to target addx in real mode
  1097.  
  1098. ;═════════════════════════════════════════════════════════════════════════════
  1099. vxr_saverestorerm:                      ; VCPI/XMS/raw save/restore status
  1100.         retf                            ; no save/restore needed, 16bit RETF
  1101.  
  1102. ;═════════════════════════════════════════════════════════════════════════════
  1103. vxr_saverestorepm:                      ; VCPI/XMS/raw save/restore status
  1104.         db 66h,0cbh                     ; no save/restore needed, 32bit RETF
  1105.  
  1106. ;═════════════════════════════════════════════════════════════════════════════
  1107. critical_error:                         ; some unrecoverable error
  1108.         cli                             ; make sure we are not interrupted
  1109.         in al,61h                       ; beep
  1110.         or al,3
  1111.         out 61h,al
  1112.         jmp $                           ; now hang
  1113.  
  1114. ;═════════════════════════════════════════════════════════════════════════════
  1115. callback:                               ; real mode callback handler
  1116.         mov ax,sp                       ; preserve SS:SP for callback
  1117.         push ss
  1118.         push ax
  1119.  
  1120.         push gs fs ds es                ; preserve real mode regs for callback
  1121.         pushf                           ; preserve FLAGS for callback
  1122.  
  1123.         cli
  1124.         cld
  1125.  
  1126.         mov ebp,cs:pmstacktop           ; EBP = ESP for protected mode
  1127.  
  1128.         mov ebx,ebp                     ; set EBX to next stack location
  1129.         sub ebx,cs:pmstacklen
  1130.         mov cs:pmstacktop,ebx           ; update ptr for possible reenterancy
  1131.  
  1132.         cmp ebx,cs:pmstackbase          ; exceeded protected mode stack space?
  1133.         jb critical_error               ; if yes, critical error (hang)
  1134.  
  1135.         xor eax,eax                     ; EAX = base address of SS
  1136.         mov ax,ss
  1137.         shl eax,4
  1138.  
  1139.     movzx ebx,sp            ; EBX = current linear SS:SP
  1140.         add ebx,eax
  1141.  
  1142.     mov es,cs:gdtseg        ; set for protected mode callback DS
  1143.     or eax,92000000h        ;  base address in GDT
  1144.         mov es:[SELCALLBACKDS+2],eax
  1145.  
  1146.         mov ax,SELZERO                  ; DS selector for protected mode
  1147.         mov dx,ax                       ; SS selector = DS selector
  1148.         mov si,SELCODE                  ; target protected mode CS:EIP
  1149.         mov edi,offset @@callbackf0
  1150.  
  1151.         jmp cs:rmtopmswrout             ; go to protected mode
  1152.  
  1153. @@callbackf0:
  1154.         mov edi,[esp+14]                ; EDI -> register structure from stack
  1155.  
  1156.         lea esi,[esp+24]                ; copy general registers from stack
  1157.         mov ecx,8                       ;  to register structure
  1158.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1159.  
  1160.         mov esi,esp                     ; copy FLAGS, ES, DS, FG, and GS
  1161.         movs word ptr es:[edi],word ptr ds:[esi]
  1162.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1163.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1164.  
  1165.         lods dword ptr ds:[esi]         ; EAX = real mode SS:SP from stack
  1166.         add ax,42                       ; adjust SP for stuff on stack
  1167.         mov es:[edi+4],eax              ; put in register structure
  1168.  
  1169.         mov ds,cs:selcallbackds         ; DS = callback DS selector
  1170.         sub edi,42                      ; EDI -> register structure
  1171.         movzx esi,ax                    ; ESI = old real mode SP
  1172.         xchg esp,ebp                    ; ESP = protected mode stack
  1173.  
  1174.         pushfd                          ; push flags for IRETD from callback
  1175.         db 66h                          ; push 32bit CS for IRETD
  1176.         push cs
  1177.         dw 6866h,@@callbackf1,0         ; push 32bit EIP for IRETD
  1178.  
  1179.         movzx eax,word ptr [ebp+22]     ; EAX = target CS of callback
  1180.         push eax                        ; push 32bit CS for RETF to callback
  1181.         push dword ptr [ebp+18]         ; push 32bit EIP for retf
  1182.  
  1183.         db 66h                          ; 32bit RETF to callback
  1184.         retf
  1185.  
  1186. @@callbackf1:
  1187.         cli
  1188.         cld
  1189.  
  1190.         push es                         ; DS:ESI = register structure
  1191.         pop ds
  1192.         mov esi,edi
  1193.  
  1194.         mov es,cs:selzero               ; ES -> 0 (beginning of memory)
  1195.  
  1196.         movzx ebx,word ptr [esi+2eh]    ; EBX = real mode SP from structure
  1197.         movzx edx,word ptr [esi+30h]    ; EDX = real mode SS from structure
  1198.         sub bx,42                       ; subtract size of vars to be put
  1199.  
  1200.         mov ebp,[esi+0ch]               ; EBP = pushed ESP from real mode
  1201.         mov bp,bx                       ; EBP = old high & new low word of ESP
  1202.  
  1203.         lea edi,[edx*4]                 ; EDI -> real mode base of stack
  1204.         lea edi,[edi*4+ebx]             ;  of vars to be stored
  1205.  
  1206.         mov ecx,8                       ; copy general registers to stack
  1207.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1208.  
  1209.         mov eax,[esi+6]                 ; EAX = return FS and GS for real mode
  1210.         mov es:[edi],eax                ; store on real mode stack for return
  1211.  
  1212.         mov ax,[esi]                    ; AX = return FLAGS for real mode
  1213.         mov es:[edi+8],ax               ; store on real mode stack for return
  1214.         mov eax,[esi+10]                ; EAX = return CS:IP for real mode
  1215.         mov es:[edi+4],eax              ; store on real mode stack for return
  1216.  
  1217.         mov ax,[esi+4]                  ; AX = return DS for real mode
  1218.         mov cx,[esi+2]                  ; CX = return ES for real mode
  1219.  
  1220.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1221.         mov di,off @@callbackf2
  1222.  
  1223.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1224.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1225.  
  1226. @@callbackf2:
  1227.         mov esp,ebp                     ; restore total ESP, old high word
  1228.  
  1229.         mov eax,cs:pmstacklen           ; restore top of protected mode stack
  1230.         add cs:pmstacktop,eax
  1231.  
  1232.         popad                           ; get callback return general regs
  1233.         pop fs gs                       ; get callback return FS and GS values
  1234.         iret                            ; go to callback return CS:IP
  1235.  
  1236. ;═════════════════════════════════════════════════════════════════════════════
  1237. intrmatrix:                ; INT redirectors for all INTs
  1238. rept 100h
  1239.         call near ptr intr              ; 3 byte CALL
  1240.         nop                             ; 1 byte NOP to align on 4
  1241. endm
  1242.  
  1243. ;═════════════════════════════════════════════════════════════════════════════
  1244. intr:                                   ; general interrupt redirector
  1245.         cli
  1246.         sub esp,2
  1247.         xchg eax,[esp]                  ; store EAX, also get CALL address
  1248.         push ecx edx ebx esp ebp esi edi; store rest of registers for POPAD
  1249.         push ds es fs gs
  1250.  
  1251.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1252.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  1253.  
  1254.         mov dx,cs:rmstacktop            ; DX = SS for real mode redirection
  1255.         movzx ebp,dx                    ; EBP -> top of real mode stack
  1256.         shl ebp,4
  1257.  
  1258.         mov bx,cs:_pm_rmstacklen        ; get size of real mode stack
  1259.         sub dx,bx                       ; adjust DX to next stack location
  1260.         mov ds:rmstacktop[edi],dx       ; update ptr for possible reenterancy
  1261.         shl bx,4                        ; set real mode SP to top of stack
  1262.  
  1263.         cmp dx,cs:rmstackbase           ; exceeded real mode stack space?
  1264.         jb critical_error               ; if yes, critical error (hang)
  1265.  
  1266.         mov ds:[ebp-2],ss               ; store SS:ESP on real mode stack
  1267.         mov ds:[ebp-6],esp
  1268.  
  1269.         shr eax,16                      ; move CALL address to AX
  1270.         sub ax,off intrmatrix           ; AX = int number, since AX is:
  1271.         shr ax,2                        ;  intrmatrix + (int number * 4)
  1272.  
  1273.         mov ah,al                       ; AH = high 5 bits of int number
  1274.         and ah,0f8h
  1275.  
  1276.         cmp ah,cs:picslave              ; high IRQ?
  1277.         je short intrirq                ; if yes, do IRQ
  1278.         cmp ah,cs:picmaster             ; low IRQ?
  1279.         jne short intrint               ; if no, do INT (with general regs)
  1280.  
  1281. ;-----------------------------------------------------------------------------
  1282. intrirq:                                ; an IRQ redirection
  1283.         mov ds:@@intrirqintnum[edi],al  ; modify code with interrupt number
  1284.  
  1285.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1286.         mov di,off @@intrirqf0
  1287.         sub bx,6                        ; adjust real mode SP for stored vars
  1288.  
  1289.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1290.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1291.  
  1292. @@intrirqf0:
  1293.         db 0cdh                         ; INT @@intrirqintnum
  1294. @@intrirqintnum db      ?
  1295.  
  1296.         mov ax,SELZERO                  ; DS selector value for protected mode
  1297.         mov cx,ax                       ; ES selector value for protected mode
  1298.         pop ebx                         ; get protected mode SS:ESP from stack
  1299.         pop dx
  1300.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1301.         mov edi,off @@intrirqf1
  1302.  
  1303.         jmp cs:rmtopmswrout             ; go back to protected mode
  1304.  
  1305. @@intrirqf1:
  1306.         mov edi,cs:codebase             ; restore top of real mode stack
  1307.         mov ax,cs:_pm_rmstacklen
  1308.         add ds:rmstacktop[edi],ax
  1309.  
  1310.         pop gs fs es ds                 ; restore all registers
  1311.         popad
  1312.         iretd
  1313.  
  1314. ;-----------------------------------------------------------------------------
  1315. intrint:                                ; an INT redirection
  1316.         mov ds:@@intrintintnum[edi],al  ; modify code with interrupt number
  1317.  
  1318.         mov es,cs:selzero               ; copy registers from protected mode
  1319.         lea edi,[ebp-26h]               ;  stack to real mode stack
  1320.         lea esi,[esp+8]
  1321.         mov ecx,8
  1322.         cld
  1323.         rep movs dword ptr es:[edi],dword ptr ss:[esi]
  1324.  
  1325.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1326.         mov di,off @@intrintf0
  1327.         sub bx,26h                      ; adjust real mode SP for stored vars
  1328.  
  1329.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1330.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1331.  
  1332. @@intrintf0:
  1333.         popad                           ; load regs with int call values
  1334.  
  1335.         db 0cdh                         ; INT @@intrirqintnum
  1336. @@intrintintnum db      ?
  1337.  
  1338.         pushad                          ; store registers on stack
  1339.         pushf                           ; store flags on stack
  1340.         cli
  1341.  
  1342.         xor eax,eax                     ; EAX = linear ptr to SS
  1343.         mov ax,ss
  1344.         shl eax,4
  1345.         movzx ebp,sp                    ; EBP = SP
  1346.  
  1347.         mov ebx,[bp+22h]                ; get protected mode SS:ESP from stack
  1348.         mov dx,[bp+26h]
  1349.  
  1350.         add ebp,eax                     ; EBP -> stored regs on stack
  1351.  
  1352.         mov ax,SELZERO                  ; DS selector value for protected mode
  1353.         mov cx,ax                       ; ES selector value for protected mode
  1354.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1355.         mov edi,off @@intrintf1
  1356.  
  1357.         jmp cs:rmtopmswrout             ; go back to protected mode
  1358.  
  1359. @@intrintf1:
  1360.         mov edi,cs:codebase             ; restore top of real mode stack
  1361.         mov ax,cs:_pm_rmstacklen
  1362.         add ds:rmstacktop[edi],ax
  1363.  
  1364.         mov ax,ds:[ebp]                 ; move return FLAGS from real mode
  1365.         mov [esp+30h],ax                ;  stack to protected mode stack
  1366.  
  1367.         mov edi,ds:[ebp+2]              ; restore return registers from real
  1368.         mov esi,ds:[ebp+6]              ;  mode stack
  1369.         mov ebx,ds:[ebp+18]
  1370.         mov edx,ds:[ebp+22]
  1371.         mov ecx,ds:[ebp+26]
  1372.         mov eax,ds:[ebp+30]
  1373.         mov ebp,ds:[ebp+10]
  1374.  
  1375.         pop gs fs es ds                 ; restore segment regs
  1376.         add esp,20h                     ; skip old general registers on stack
  1377.         iretd
  1378.  
  1379. ;═════════════════════════════════════════════════════════════════════════════
  1380. int21:                                  ; watch for INT 21h AH=4Ch
  1381.         cmp ah,4ch                      ; AH = 4Ch?
  1382.         jne intrmatrix+4*21h            ; if no, go to INT 21h redirection
  1383.  
  1384.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1385.         mov edi,cs:codebase             ; EDI = offset of PMODE_TEXT from 0
  1386.  
  1387.         mov ebx,cs:oldint15vector       ; put back old INT 15h handler
  1388.         mov ds:[4*15h],ebx
  1389.  
  1390.         jmp intrmatrix+4*21h            ; go to INT 21h redirection
  1391.  
  1392. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1393. ; INT 31h INTERFACE
  1394. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1395.  
  1396. ;═════════════════════════════════════════════════════════════════════════════
  1397. int31:                                  ; protected mode INT 31h handler
  1398.         cli
  1399.         cld
  1400.         push ds es fs gs                ; push regs needed
  1401.         pushad
  1402.         mov ds,cs:selzero               ; DS -> 0 (beginning of memory)
  1403.  
  1404.         push bx
  1405.         mov bx,(INT31FUNCNUM - 1) * 2   ; number of functions to check
  1406. @@int31l0:
  1407.         cmp ax,cs:int31functbl[bx]      ; found function value?
  1408.         jne short @@int31l0c
  1409.  
  1410.         mov bx,cs:int31routtbl[bx]      ; yes, go to appropriate handler
  1411.         xchg bx,[esp]
  1412.         ret
  1413.  
  1414. @@int31l0c:
  1415.         sub bx,2                        ; no, continue loop
  1416.         jnc @@int31l0
  1417.  
  1418.         pop bx                          ; no function found
  1419.         jmp int31fail8001               ; error 8001h
  1420.  
  1421. ;-----------------------------------------------------------------------------
  1422. int31fail8024:                          ; INT 31h return fail with error 8024h
  1423.         mov word ptr [esp+28],8024h     ; set AX on stack to 8024h for POPAD
  1424.         jmp short int31fail
  1425.  
  1426. ;-----------------------------------------------------------------------------
  1427. int31fail8023:                          ; INT 31h return fail with error 8023h
  1428.         mov word ptr [esp+28],8023h     ; set AX on stack to 8023h for POPAD
  1429.         jmp short int31fail
  1430.  
  1431. ;-----------------------------------------------------------------------------
  1432. int31fail8022:                          ; INT 31h return fail with error 8022h
  1433.         mov word ptr [esp+28],8022h     ; set AX on stack to 8022h for POPAD
  1434.         jmp short int31fail
  1435.  
  1436. ;-----------------------------------------------------------------------------
  1437. int31fail8021:                          ; INT 31h return fail with error 8021h
  1438.         mov word ptr [esp+28],8021h     ; set AX on stack to 8021h for POPAD
  1439.         jmp short int31fail
  1440.  
  1441. ;-----------------------------------------------------------------------------
  1442. int31fail8016:                          ; INT 31h return fail with error 8016h
  1443.         mov word ptr [esp+28],8016h     ; set AX on stack to 8016h for POPAD
  1444.         jmp short int31fail
  1445.  
  1446. ;-----------------------------------------------------------------------------
  1447. int31fail8015:                          ; INT 31h return fail with error 8015h
  1448.         mov word ptr [esp+28],8015h     ; set AX on stack to 8015h for POPAD
  1449.         jmp short int31fail
  1450.  
  1451. ;-----------------------------------------------------------------------------
  1452. int31fail8013:                          ; INT 31h return fail with error 8013h
  1453.         mov word ptr [esp+28],8013h     ; set AX on stack to 8013h for POPAD
  1454.         jmp short int31fail
  1455.  
  1456. ;-----------------------------------------------------------------------------
  1457. int31fail8012:                          ; INT 31h return fail with error 8012h
  1458.         mov word ptr [esp+28],8012h     ; set AX on stack to 8012h for POPAD
  1459.         jmp short int31fail
  1460.  
  1461. ;-----------------------------------------------------------------------------
  1462. int31fail8011:                          ; INT 31h return fail with error 8011h
  1463.         mov word ptr [esp+28],8011h     ; set AX on stack to 8011h for POPAD
  1464.         jmp short int31fail
  1465.  
  1466. ;-----------------------------------------------------------------------------
  1467. int31fail8010:                          ; INT 31h return fail with error 8010h
  1468.         mov word ptr [esp+28],8010h     ; set AX on stack to 8010h for POPAD
  1469.         jmp short int31fail
  1470.  
  1471. ;-----------------------------------------------------------------------------
  1472. int31fail8001:                          ; INT 31h return fail with error 8001h
  1473.         mov word ptr [esp+28],8001h     ; set AX on stack to 8001h for POPAD
  1474.         jmp short int31fail
  1475.  
  1476. ;-----------------------------------------------------------------------------
  1477. int31failcx:                            ; INT 31h return fail with CX,AX
  1478.         mov word ptr [esp+24],cx        ; put CX onto stack for POPAD
  1479.  
  1480. ;-----------------------------------------------------------------------------
  1481. int31failax:                            ; INT 31h return fail with AX
  1482.         mov word ptr [esp+28],ax        ; put AX onto stack for POPAD
  1483.  
  1484. ;-----------------------------------------------------------------------------
  1485. int31fail:                              ; INT 31h return fail, pop all regs
  1486.         popad
  1487.         pop gs fs es ds
  1488.  
  1489. ;-----------------------------------------------------------------------------
  1490. int31failnopop:                         ; INT 31h return fail with carry set
  1491.         or byte ptr [esp+8],1           ; set carry in EFLAGS on stack
  1492.         iretd
  1493.  
  1494. ;-----------------------------------------------------------------------------
  1495. int31okdx:                              ; INT 31h return ok with DX,CX,AX
  1496.         mov [esp+20],dx                 ; put CX onto stack for POPAD
  1497.         jmp short int31okcx
  1498.  
  1499. ;-----------------------------------------------------------------------------
  1500. int31oksinoax:                          ; INT 31h return ok SI,DI,BX,CX
  1501.         mov ax,[esp+28]                 ; get old value of AX for restore
  1502.  
  1503. ;-----------------------------------------------------------------------------
  1504. int31oksi:                              ; INT 31h return ok SI,DI,BX,CX,AX
  1505.         mov [esp+4],si                  ; put SI onto stack for POPAD
  1506.         mov [esp],di                    ; put DI onto stack for POPAD
  1507.         mov [esp+16],bx                 ; put BX onto stack for POPAD
  1508.  
  1509. ;-----------------------------------------------------------------------------
  1510. int31okcx:                              ; INT 31h return ok with CX,AX
  1511.         mov [esp+24],cx                 ; put CX onto stack for POPAD
  1512.  
  1513. ;-----------------------------------------------------------------------------
  1514. int31okax:                              ; INT 31h return ok with AX
  1515.         mov [esp+28],ax                 ; put AX onto stack for POPAD
  1516.  
  1517. ;-----------------------------------------------------------------------------
  1518. int31ok:                                ; INT 31h return ok, pop all regs
  1519.         popad
  1520.         pop gs fs es ds
  1521.  
  1522. ;-----------------------------------------------------------------------------
  1523. int31oknopop:                           ; INT 31h return ok with carry clear
  1524.         and byte ptr [esp+8],0feh       ; clear carry in EFLAGS on stack
  1525.         iretd
  1526.  
  1527. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1528. ; DESCRIPTOR FUNCTIONS
  1529. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1530.  
  1531. ;-----------------------------------------------------------------------------
  1532. int31testsel:                           ; test for valid selector BX
  1533.         pop bp                          ; pop return address
  1534.  
  1535.         cmp bx,cs:gdtlimit              ; selector BX out of range?
  1536.         ja int31fail8022                ; if yes, fail with error 8022h
  1537.  
  1538.         mov edi,cs:gdtbase              ; get base of GDT
  1539.         and bl,0f8h                     ; mask offset table index and RPL
  1540.         movzx ebx,bx                    ; EBX = selector index
  1541.         test byte ptr ds:[edi+ebx+6],10h; is descriptor used?
  1542.         jz int31fail8022                ; if descriptor not used, fail 8022h
  1543.  
  1544.         jmp bp                          ; return ok
  1545.  
  1546. ;-----------------------------------------------------------------------------
  1547. int31testaccess:                        ; test access bits in CX
  1548.         pop bp                          ; pop return address
  1549.  
  1550.         test ch,20h                     ; test MUST BE 0 bit in CH
  1551.         jnz int31fail8021               ; if not 0, error 8021h
  1552.  
  1553.         test cl,90h                     ; test present and MUST BE 1 bits
  1554.         jz int31fail8021                ; if both 0, error 8021h
  1555.         jpo int31fail8021               ; if unequal, error 8021h
  1556.  
  1557.         test cl,60h                     ; test DPL
  1558.         jnz int31fail8021               ; if not 0, error 8021h
  1559.  
  1560.         test cl,8                       ; if code, more tests needed
  1561.         jz short @@int31testselok       ; if data, skip code tests
  1562.  
  1563.         test cl,6                       ; test conforming and readable bits
  1564.         jz int31fail8021                ; if both 0, error 8021h
  1565.         jpe int31fail8021               ; if equal, error 8021h
  1566.  
  1567. @@int31testselok:
  1568.         jmp bp                          ; return ok
  1569.  
  1570. ;─────────────────────────────────────────────────────────────────────────────
  1571. int310000:                              ; allocate descriptors
  1572.         or cx,cx                        ; if CX = 0, error 8021h
  1573.         jz int31fail8021
  1574.  
  1575.         mov edx,cs:gdtbase              ; get base of GDT
  1576.         movzx eax,cs:gdtlimit           ; EAX = last selector index
  1577.         and al,0f8h
  1578.  
  1579.         mov bx,cx                       ; BX = number of selectors to find
  1580. @@int310000l0:
  1581.         test byte ptr ds:[edx+eax+6],10h; is descriptor used?
  1582.         jnz short @@int310000l0f0
  1583.  
  1584.         dec bx                          ; found free descriptor, dec counter
  1585.         jnz short @@int310000l0f1       ; continue if need to find more
  1586.  
  1587.         mov ebx,eax                     ; found all descriptors requested
  1588. @@int310000l1:
  1589.         mov dword ptr ds:[edx+ebx],0    ; set entire new descriptor
  1590.         mov dword ptr ds:[edx+ebx+4],109200h
  1591.         add bx,8                        ; increment selector index
  1592.         dec cx                          ; dec counter of descriptors to mark
  1593.         jnz @@int310000l1               ; loop if more to mark
  1594.  
  1595.         jmp int31okax                   ; return ok, with AX
  1596.  
  1597. @@int310000l0f0:
  1598.         mov bx,cx                       ; reset number of selectors to find
  1599.  
  1600. @@int310000l0f1:
  1601.         sub ax,8                        ; dec current selector counter
  1602.         cmp ax,8*SYSSELECTORS           ; more descriptors to go?
  1603.         jae @@int310000l0               ; if yes, loop
  1604.  
  1605.         jmp int31fail8011               ; did not find descriptors
  1606.  
  1607. ;─────────────────────────────────────────────────────────────────────────────
  1608. int310001:                              ; free descriptor
  1609.         call int31testsel               ; test for valid selector BX
  1610.  
  1611.         and byte ptr ds:[edi+ebx+6],0efh; mark descriptor as free
  1612.  
  1613.         mov cx,4                        ; zero any segregs loaded with BX
  1614.         lea ebp,[esp+32]                ; EBP -> selectors on stack
  1615. @@int310001l0:
  1616.         cmp word ptr [ebp],bx           ; selector = BX?
  1617.         jne short @@int310001l0f0       ; if no, continue loop
  1618.  
  1619.         mov word ptr [ebp],0            ; zero selector on stack
  1620.  
  1621. @@int310001l0f0:
  1622.         add ebp,2                       ; increment selector ptr
  1623.         loop @@int310001l0              ; loop
  1624.  
  1625.         jmp int31ok                     ; return ok
  1626.  
  1627. ;─────────────────────────────────────────────────────────────────────────────
  1628. int310003:                              ; get selector increment value
  1629.         mov ax,8                        ; selector increment value is 8
  1630.         jmp int31okax                   ; return ok, with AX
  1631.  
  1632. ;─────────────────────────────────────────────────────────────────────────────
  1633. int310006:                              ; get segment base address
  1634.         call int31testsel               ; test for valid selector BX
  1635.  
  1636.         mov dx,word ptr ds:[edi+ebx+2]  ; low word of 32bit linear address
  1637.         mov cl,byte ptr ds:[edi+ebx+4]  ; high word of 32bit linear address
  1638.         mov ch,byte ptr ds:[edi+ebx+7]
  1639.  
  1640.         jmp int31okdx                   ; return ok, with DX, CX, AX
  1641.  
  1642. ;─────────────────────────────────────────────────────────────────────────────
  1643. int310007:                              ; set segment base address
  1644.         call int31testsel               ; test for valid selector BX
  1645.  
  1646.         mov word ptr ds:[edi+ebx+2],dx  ; low word of 32bit linear address
  1647.         mov byte ptr ds:[edi+ebx+4],cl  ; high word of 32bit linear address
  1648.         mov byte ptr ds:[edi+ebx+7],ch
  1649.  
  1650.         jmp int31ok                     ; return ok
  1651.  
  1652. ;─────────────────────────────────────────────────────────────────────────────
  1653. int310008:                              ; set segment limit
  1654.         call int31testsel               ; test for valid selector BX
  1655.  
  1656.         cmp cx,0fh                      ; limit greater than 1M?
  1657.         jbe short @@int310008f0
  1658.  
  1659.         mov ax,dx                       ; yup, limit greater than 1M
  1660.         and ax,0fffh
  1661.         cmp ax,0fffh                    ; low 12 bits set?
  1662.         jne int31fail8021               ; if no, error 8021h
  1663.  
  1664.         shrd dx,cx,12                   ; DX = low 16 bits of page limit
  1665.         shr cx,12                       ; CL = high 4 bits of page limit
  1666.         or cl,80h                       ; set granularity bit in CL
  1667.  
  1668. @@int310008f0:
  1669.         mov word ptr ds:[edi+ebx],dx    ; put low word of limit
  1670.         and byte ptr ds:[edi+ebx+6],70h ; mask off G and high nybble of limit
  1671.         or byte ptr ds:[edi+ebx+6],cl   ; put high nybble of limit
  1672.  
  1673.         jmp int31ok                     ; return ok
  1674.  
  1675. ;─────────────────────────────────────────────────────────────────────────────
  1676. int310009:                              ; set descriptor access rights
  1677.         call int31testsel               ; test for valid selector BX
  1678.  
  1679.         call int31testaccess            ; test access bits in CX
  1680.  
  1681.         or ch,10h                       ; set AVL bit, descriptor used
  1682.         and ch,0f0h                     ; mask off low nybble of CH
  1683.         and byte ptr ds:[edi+ebx+6],0fh ; mask off high nybble access rights
  1684.         or byte ptr ds:[edi+ebx+6],ch   ; or in high access rights byte
  1685.         mov byte ptr ds:[edi+ebx+5],cl  ; put low access rights byte
  1686.  
  1687.         jmp int31ok                     ; return ok
  1688.  
  1689. ;─────────────────────────────────────────────────────────────────────────────
  1690. int31000a:                              ; create alias descriptor
  1691.         call int31testsel               ; test for valid selector BX
  1692.  
  1693.         mov ax,0000h                    ; allocate descriptor
  1694.         mov cx,1
  1695.         int 31h
  1696.         jc int31fail8011                ; if failed, descriptor unavailable
  1697.  
  1698.         push ax                         ; preserve allocated selector
  1699.  
  1700.         push ds                         ; copy descriptor and set type data
  1701.         pop es
  1702.         movzx edi,ax                    ; EDI = target selector
  1703.         mov esi,cs:gdtbase              ; ESI -> GDT
  1704.         add edi,esi                     ; adjust to target descriptor in GDT
  1705.         add esi,ebx                     ; adjust to source descriptor in GDT
  1706.  
  1707.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1708.         lods dword ptr ds:[esi]
  1709.         mov ah,92h                      ; set descriptor type - R/W up data
  1710.         stos dword ptr es:[edi]
  1711.  
  1712.         pop ax                          ; restore allocated selector
  1713.  
  1714.         jmp int31okax                   ; return ok, with AX
  1715.  
  1716. ;─────────────────────────────────────────────────────────────────────────────
  1717. int31000b:                              ; get descriptor
  1718.         call int31testsel               ; test for valid selector BX
  1719.  
  1720.         lea esi,[edi+ebx]               ; ESI -> descriptor in GDT
  1721.         mov edi,[esp]                   ; get EDI buffer ptr from stack
  1722.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1723.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1724.  
  1725.         jmp int31ok                     ; return ok
  1726.  
  1727. ;─────────────────────────────────────────────────────────────────────────────
  1728. int31000c:                              ; set descriptor
  1729.         call int31testsel               ; test for valid selector BX
  1730.  
  1731.         mov esi,[esp]                   ; ESI = EDI buffer ptr from stack
  1732.         mov cx,es:[esi+5]               ; get access rights from descriptor
  1733.         call int31testaccess            ; test access bits in CX
  1734.  
  1735.         push ds                         ; swap DS and ES, target and source
  1736.         push es
  1737.         pop ds
  1738.         pop es
  1739.  
  1740.         add edi,ebx                     ; adjust EDI to descriptor in GDT
  1741.         movs dword ptr es:[edi],dword ptr ds:[esi]      ; copy descriptor
  1742.         lods dword ptr ds:[esi]
  1743.         or eax,100000h                  ; set descriptor AVL bit
  1744.         stos dword ptr es:[edi]
  1745.  
  1746.         jmp int31ok                     ; return ok
  1747.  
  1748. ;─────────────────────────────────────────────────────────────────────────────
  1749. int31000e:                              ; get multiple descriptors
  1750.         mov ax,000bh                    ; function 000bh, get descriptor
  1751.  
  1752. ;-----------------------------------------------------------------------------
  1753. int31000ef:                             ; common to funcions 000eh and 000fh
  1754.         or cx,cx                        ; if CX = 0, return ok immediately
  1755.         jz int31ok
  1756.  
  1757.         mov dx,cx                       ; DX = number of descriptors
  1758.         xor cx,cx                       ; CX = successful counter
  1759. @@int31000efl0:
  1760.         mov bx,es:[edi]                 ; BX = selector to get
  1761.         add edi,2
  1762.  
  1763.         int 31h                         ; get/set descriptor
  1764.         jc int31failcx                  ; if error, fail with AX and CX
  1765.  
  1766.         add edi,8                       ; increment descriptor ptr
  1767.         inc cx                          ; increment successful copy counter
  1768.         dec dx                          ; decrement loop counter
  1769.         jnz @@int31000efl0              ; if more descriptors to go, loop
  1770.  
  1771.         jmp int31ok                     ; return ok
  1772.  
  1773. ;─────────────────────────────────────────────────────────────────────────────
  1774. int31000f:                              ; set multiple descriptors
  1775.         mov ax,000ch                    ; function 000ch, set descriptor
  1776.  
  1777.         jmp int31000ef                  ; go to common function
  1778.  
  1779. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1780. ; INTERRUPT FUNCTIONS
  1781. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1782.  
  1783. ;─────────────────────────────────────────────────────────────────────────────
  1784. int310200:                              ; get real mode interrupt vector
  1785.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1786.         mov dx,ds:[ebx*4]               ; load real mode vector offset
  1787.         mov cx,ds:[ebx*4+2]             ; load real mode vector segment
  1788.  
  1789.         jmp int31okdx                   ; return ok, with AX, CX, DX
  1790.  
  1791. ;─────────────────────────────────────────────────────────────────────────────
  1792. int310201:                              ; set real mode interrupt vector
  1793.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1794.         mov ds:[ebx*4],dx               ; set real mode vector offset
  1795.         mov ds:[ebx*4+2],cx             ; set real mode vector segment
  1796.  
  1797.         jmp int31ok                     ; return ok
  1798.  
  1799. ;─────────────────────────────────────────────────────────────────────────────
  1800. int310204:                              ; get protected mode interrupt vector
  1801.         movzx ebx,bl                    ; EBX = BL (interrupt number)
  1802.         shl ebx,3                       ; adjust for location in IDT
  1803.         add ebx,cs:idtbase              ; add base of IDT
  1804.  
  1805.         mov edx,dword ptr ds:[ebx+4]    ; get high word of offset
  1806.         mov dx,word ptr ds:[ebx]        ; get low word of offset
  1807.         mov cx,word ptr ds:[ebx+2]      ; get selector
  1808.  
  1809.         jmp int31okdx                   ; return ok, with AX, CX, DX
  1810.  
  1811. ;─────────────────────────────────────────────────────────────────────────────
  1812. int310205:                              ; set protected mode interrupt vector
  1813.         xchg bx,cx                      ; swap int number with int selector
  1814.         call int31testsel               ; test for valid selector BX
  1815.  
  1816.         movzx ecx,cl                    ; ECX = CL (interrupt number)
  1817.         shl ecx,3                       ; adjust for location in IDT
  1818.         add ecx,cs:idtbase              ; add base of IDT
  1819.  
  1820.         mov word ptr ds:[ecx],dx        ; set low word of offset
  1821.         shr edx,16
  1822.         mov word ptr ds:[ecx+6],dx      ; set high word of offset
  1823.         mov word ptr ds:[ecx+2],bx      ; set selector
  1824.  
  1825.         jmp int31ok                     ; return ok
  1826.  
  1827. ;─────────────────────────────────────────────────────────────────────────────
  1828. int310900:                              ; get and disable interrupt state
  1829.         add esp,26h                     ; adjust stack
  1830.         pop ds                          ; restore DS
  1831.  
  1832.         btc word ptr [esp+8],9          ; test and clear IF bit in EFLAGS
  1833.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1834.  
  1835.         jmp int31oknopop                ; return ok, dont pop registers
  1836.  
  1837. ;─────────────────────────────────────────────────────────────────────────────
  1838. int310901:                              ; get and enable interrupt state
  1839.         add esp,26h                     ; adjust stack
  1840.         pop ds                          ; restore DS
  1841.  
  1842.         bts word ptr [esp+8],9          ; test and set IF bit in EFLAGS
  1843.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1844.  
  1845.         jmp int31oknopop                ; return ok, dont pop registers
  1846.  
  1847. ;─────────────────────────────────────────────────────────────────────────────
  1848. int310902:                              ; get interrupt state
  1849.         add esp,26h                     ; adjust stack
  1850.         pop ds                          ; restore DS
  1851.  
  1852.         bt word ptr [esp+8],9           ; just test IF bit in EFLAGS
  1853.         setc al                         ; set AL = carry (IF flag from EFLAGS)
  1854.  
  1855.         jmp int31oknopop                ; return ok, dont pop registers
  1856.  
  1857. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1858. ; REAL/PROTECTED MODE TRANSLATION FUNCTIONS
  1859. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1860.  
  1861. ;─────────────────────────────────────────────────────────────────────────────
  1862. int310300:                              ; simulate real mode interrupt
  1863.         movzx ebx,bl                    ; get real mode INT CS:IP
  1864.         mov ebp,dword ptr ds:[ebx*4]
  1865.  
  1866. ;-----------------------------------------------------------------------------
  1867. int31030012:                            ; common to 0300h, 0301h, and 0302h
  1868.         mov esi,cs:codebase             ; ESI = offset of PMODE_TEXT from 0
  1869.  
  1870.         movzx ebx,word ptr es:[edi+2eh] ; EBX = SP from register structure
  1871.         movzx edx,word ptr es:[edi+30h] ; EDX = SS from register structure
  1872.  
  1873.         mov ax,bx                       ; check if caller provided stack
  1874.         or ax,dx
  1875.         jnz short @@int31030012f3       ; if yes, go on to set stack
  1876.  
  1877.         mov dx,cs:rmstacktop            ; DX = SS for real mode redirection
  1878.         mov bx,cs:_pm_rmstacklen        ; get size of real mode stack
  1879.         sub dx,bx                       ; adjust DX to next stack location
  1880.  
  1881.         cmp dx,cs:rmstackbase           ; exceeded real mode stack space?
  1882.         jb int31fail8012                ; if yes, error 8012h
  1883.  
  1884.         mov ds:rmstacktop[esi],dx       ; update ptr for possible reenterancy
  1885.         shl bx,4                        ; adjust BX from paragraphs to bytes
  1886.  
  1887. @@int31030012f3:
  1888.         lea edi,[edx*4]                 ; EDI -> top of real mode stack
  1889.         lea edi,[edi*4+ebx]
  1890.  
  1891.         movzx ax,byte ptr [esp+28]      ; AX = AL of original INT 31h call
  1892.         and al,1                        ; if function 0301h, AL=0, else, AL=2
  1893.         xor al,1
  1894.         shl al,1
  1895.         sub bx,ax                       ; adjust BX for possible FLAGS
  1896.  
  1897.         lea eax,[ecx*2]                 ; EAX = length of stack parms
  1898.  
  1899.         sub bx,ax                       ; adjust real mode SP for stored vars
  1900.         sub bx,36h
  1901.  
  1902.         xchg ax,ds:rmstackparmlen[esi]  ; store length of stack parms, save
  1903.         push ax                         ;  old value for possible reenterancy
  1904.  
  1905.         mov ds:[edi-2],ss               ; store SS:ESP on real mode stack
  1906.         mov ds:[edi-6],esp
  1907.         mov ds:[edi-8],es               ; store ES on real mode stack
  1908.  
  1909.         push ds                         ; swap DS and ES
  1910.         push es
  1911.         pop ds
  1912.         pop es
  1913.  
  1914.         std                             ; string copy backwards
  1915.  
  1916.         sub edi,10                      ; copy stack parms from protected mode
  1917.         movzx ecx,cx                    ;  stack to real mode stack
  1918.         lea esi,[esp+ecx*2+36h-2]
  1919.         rep movs word ptr es:[edi],word ptr ss:[esi]
  1920.  
  1921.         mov esi,[esp+2]                 ; ESI = offset of structure from stack
  1922.         mov ax,[esi+20h]                ; AX = FLAGS from register structure
  1923.  
  1924.         mov es:[edi],ax                 ; store data for real mode return IRET
  1925.  
  1926.         cmp byte ptr [esp+30],1         ; check AL on stack for function code
  1927.         je short @@int31030012f4        ; if function 0301h, go on
  1928.  
  1929.         and ah,0fch                     ; 0300h or 0302h, clear IF and TF flag
  1930.  
  1931. @@int31030012f4:
  1932.         cld                             ; string copy forward
  1933.         lea edi,[edx*4]                 ; EDI -> bottom of stack
  1934.         lea edi,[edi*4+ebx]
  1935.  
  1936.         mov ecx,8                       ; copy general regs to real mode stack
  1937.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  1938.  
  1939.         add esi,6                       ; copy FS and GS to real mode stack
  1940.         movs dword ptr es:[edi],dword ptr ds:[esi]
  1941.  
  1942.         mov word ptr es:[edi+8],PMODE_TEXT      ; return address from call
  1943.         mov word ptr es:[edi+6],off @@int31030012f1
  1944.  
  1945.         mov es:[edi+4],ax               ; store FLAGS for real mode IRET maybe
  1946.         mov dword ptr es:[edi],ebp      ; put call address to real mode stack
  1947.  
  1948.         mov ax,[esi-6]                  ; real mode DS from register structure
  1949.         mov cx,[esi-8]                  ; real mode ES from register structure
  1950.  
  1951.         mov si,PMODE_TEXT               ; real mode target CS:IP
  1952.         mov di,off @@int31030012f0
  1953.  
  1954.         db 66h                          ; JMP DWORD PTR, as in 32bit offset,
  1955.         jmp word ptr cs:pmtormswrout    ;  not seg:16bit offset
  1956.  
  1957. @@int31030012f0:                        ; real mode INT, FAR, or IRET call
  1958.         popad                           ; load regs with call values
  1959.         pop fs gs
  1960.  
  1961.         iret                            ; go to call address
  1962.  
  1963. @@int31030012f1:
  1964.         add sp,cs:rmstackparmlen        ; remove stack parameters
  1965.  
  1966.         push gs fs ds es                ; store registers on stack
  1967.         pushf                           ; store flags on stack
  1968.         pushad
  1969.         cli
  1970.  
  1971.         mov ax,ss                       ; EAX = linear ptr to SS
  1972.         movzx eax,ax
  1973.         shl eax,4
  1974.         movzx ebp,sp                    ; EBP = SP
  1975.  
  1976.         mov cx,[bp+2ah]                 ; get protected mode ES from stack
  1977.         mov ebx,[bp+2ch]                ; get protected mode SS:ESP from stack
  1978.         mov dx,[bp+30h]
  1979.  
  1980.         add ebp,eax                     ; EBP -> stored regs on stack
  1981.  
  1982.         mov ax,SELZERO                  ; DS selector value for protected mode
  1983.         mov si,SELCODE                  ; target CS:EIP in protected mode
  1984.         mov edi,off @@int31030012f2
  1985.  
  1986.         jmp cs:rmtopmswrout             ; go back to protected mode
  1987.  
  1988. @@int31030012f2:
  1989.         mov edi,cs:codebase             ; restore old stack parameter length
  1990.         pop ds:rmstackparmlen[edi]
  1991.  
  1992.         mov edi,[esp]                   ; get structure offset from stack
  1993.         mov esi,ebp                     ; copy return regs from real mode
  1994.         mov ecx,15h                     ;  stack to register structure
  1995.         cld
  1996.         rep movs word ptr es:[edi],word ptr ds:[esi]
  1997.  
  1998.         cmp dword ptr es:[edi+4],0      ; stack provided by caller?
  1999.         jne int31ok                     ; if yes, done now
  2000.  
  2001.         mov edi,cs:codebase             ; restore top of real mode stack
  2002.         mov ax,cs:_pm_rmstacklen
  2003.         add ds:rmstacktop[edi],ax
  2004.  
  2005.         jmp int31ok                     ; return ok
  2006.  
  2007. ;─────────────────────────────────────────────────────────────────────────────
  2008. int310301:                              ; call real mode FAR procedure
  2009.                                         ; same start as function 0302h
  2010. ;─────────────────────────────────────────────────────────────────────────────
  2011. int310302:                              ; call real mode IRET procedure
  2012.         mov ebp,dword ptr es:[edi+2ah]  ; get target CS:IP from structure
  2013.         jmp int31030012                 ; go to common code
  2014.  
  2015. ;─────────────────────────────────────────────────────────────────────────────
  2016. int310303:                              ; allocate real mode callback address
  2017.         mov bl,cs:_pm_callbacks         ; CL = total number of callbacks
  2018.         or bl,bl                        ; are there any?
  2019.         jz int31fail8015                ; if no, error 8015h
  2020.  
  2021.         mov edx,cs:callbackbase         ; EDX -> base of callbacks
  2022.         mov ecx,edx                     ; for later use
  2023.  
  2024. @@int310303l0:
  2025.         cmp word ptr [edx+3],0          ; is this callback free?
  2026.         jz short @@int310303f0          ; if yes, allocate
  2027.  
  2028.         add edx,25                      ; increment ptr to callback
  2029.         dec bl                          ; decrement loop counter
  2030.         jnz @@int310303l0               ; if more callbacks to check, loop
  2031.  
  2032.         jmp int31fail8015               ; no free callback, error 8015h
  2033.  
  2034. @@int310303f0:
  2035.         mov bx,[esp+38]                 ; BX = caller DS from stack
  2036.         mov [edx+3],bx                  ; store callback parms in callback
  2037.         mov [edx+7],esi
  2038.         mov [edx+12],es
  2039.         mov [edx+16],edi
  2040.  
  2041.         sub edx,ecx                     ; DX = offset of callback
  2042.         shr ecx,4                       ; CX = segment of callback
  2043.  
  2044.         jmp int31okdx                   ; return ok, with DX, CX, AX
  2045.  
  2046. ;─────────────────────────────────────────────────────────────────────────────
  2047. int310304:                              ; free real mode callback address
  2048.         cmp cx,cs:callbackseg           ; valid callback segment?
  2049.         jne int31fail8024               ; if no, error 8024h
  2050.  
  2051.         movzx ebx,dx                    ; EBX = offset of callback
  2052.  
  2053.         xor ax,ax                       ; check if valid offset
  2054.         xchg dx,ax
  2055.         mov cx,25
  2056.         div cx
  2057.  
  2058.         or dx,dx                        ; is there a remainder
  2059.         jnz int31fail8024               ; if yes, not valid, error 8024h
  2060.  
  2061.         or ah,ah                        ; callback index too big?
  2062.         jnz int31fail8024               ; if yes, not valid, error 8024h
  2063.  
  2064.         cmp al,cs:_pm_callbacks         ; callback index out of range?
  2065.         jae int31fail8024               ; if yes, not valid, error 8024h
  2066.  
  2067.         add ebx,cs:callbackbase         ; EBX -> callback
  2068.         mov word ptr [ebx+3],0          ; set callback as free
  2069.  
  2070.         jmp int31ok                     ; return ok
  2071.  
  2072. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2073. ; MISC FUNCTIONS
  2074. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2075.  
  2076. ;─────────────────────────────────────────────────────────────────────────────
  2077. int310305:                              ; get state save/restore addresses
  2078.         add esp,26h                     ; adjust stack
  2079.         pop ds                          ; restore DS
  2080.  
  2081.         xor ax,ax                       ; size needed is none
  2082.         mov bx,PMODE_TEXT               ; real mode seg of same RETF
  2083.         mov cx,off vxr_saverestorerm    ; same offset of 16bit RETF
  2084.         mov si,cs                       ; selector of routine is this one
  2085.         mov edi,off vxr_saverestorepm   ; offset of simple 32bit RETF
  2086.  
  2087.         jmp int31oknopop                ; return ok, dont pop registers
  2088.  
  2089. ;─────────────────────────────────────────────────────────────────────────────
  2090. int310306:                              ; get raw mode switch addresses
  2091.         add esp,26h                     ; adjust stack
  2092.         pop ds                          ; restore DS
  2093.  
  2094.         mov si,cs                       ; selector of pmtorm rout is this one
  2095.         mov edi,cs:pmtormswrout         ; offset in this seg of rout
  2096.         mov bx,PMODE_TEXT               ; real mode seg of rmtopm rout
  2097.         mov cx,cs:rmtopmswrout          ; offset of rout in real mode
  2098.  
  2099.         jmp int31oknopop                ; return ok, dont pop registers
  2100.  
  2101. ;─────────────────────────────────────────────────────────────────────────────
  2102. int310400:                              ; get version
  2103.         add esp,26h                     ; adjust stack
  2104.         pop ds                          ; restore DS
  2105.  
  2106.         mov ax,100h                     ; return version 1.0
  2107.         mov bx,3                        ; capabilities
  2108.         mov cl,cs:processortype         ; processor type
  2109.         mov dx,word ptr cs:picslave     ; master and slave PIC values
  2110.  
  2111.         jmp int31oknopop                ; return ok, dont pop registers
  2112.  
  2113. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2114. ; VCPI EXTENDED MEMORY FUNCTIONS
  2115. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2116.  
  2117. ;-----------------------------------------------------------------------------
  2118. int310500vsiditoesi:                    ; convert handle SI:DI to ptr ESI
  2119.         pop bp                          ; pop return address
  2120.  
  2121.         test di,3                       ; is handle (ptr) aligned on dword?
  2122.         jnz int31fail8023               ; if no, error 8023h
  2123.  
  2124.         shl esi,16                      ; ESI = SI:DI
  2125.         mov si,di
  2126.  
  2127.         cmp esi,cs:pagetablebase        ; handle too low?
  2128.         jb int31fail8023                ; if yes, error 8023h
  2129.  
  2130.         cmp esi,cs:pagetabletop         ; handle too high?
  2131.         jae int31fail8023               ; if yes, error 8023h
  2132.  
  2133.         test byte ptr [esi+1],2         ; is page first in allocated block?
  2134.         jz int31fail8023                ; if no, error 8023h
  2135.  
  2136.         jmp bp                          ; return ok
  2137.  
  2138. ;-----------------------------------------------------------------------------
  2139. int310500vbxcxtoebx:                    ; convert BX:CX bytes to EBX pages
  2140.         pop bp                          ; pop return address
  2141.  
  2142.         shl ebx,16                      ; EBX = BX:CX
  2143.         mov bx,cx
  2144.  
  2145.         or ebx,ebx                      ; check for invalid value
  2146.         jz int31fail8021                ; if invalid value, error 8021h
  2147.  
  2148.         add ebx,0fffh                   ; convert EBX to page count
  2149.         shr ebx,12
  2150.  
  2151.         jmp bp                          ; return ok
  2152.  
  2153. ;-----------------------------------------------------------------------------
  2154. int310500vpmalloc:                      ; allocate physical memory block
  2155.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2156.         xor ebp,ebp                     ; EBP = running allocated page count
  2157.  
  2158. @@int310500vpmallocl0:
  2159.         mov ax,0de04h                   ; VCPI allocate a page
  2160.         call fword ptr cs:vcpi_calleip
  2161.  
  2162.         or ah,ah                        ; got a page?
  2163.     jz short @@int310500vpmallocl0f0; if yes, go on
  2164.  
  2165.     cmp ebp,1            ; allocated any pages?
  2166.     jc short @@int310500vpmallocdone; if no, fail immediately
  2167.  
  2168.     or byte ptr [edi-3],4        ; set last allocated page as last
  2169.  
  2170.     call int310500vfree        ; free what was allocated
  2171.  
  2172.     stc                ; carry set, failed
  2173.     jmp short @@int310500vpmallocdone    ; go to done
  2174.  
  2175. @@int310500vpmallocl0f0:
  2176.         or dl,7                         ; set page as user/writeable/present
  2177.         mov [edi],edx                   ; store page in page table
  2178.     add edi,4            ; increment page table ptr
  2179.  
  2180.     inc ebp             ; increment allocated page count
  2181.     cmp ebp,ebx            ; allocated all needed pages?
  2182.     jb @@int310500vpmallocl0    ; if no, loop
  2183.  
  2184.         or byte ptr [esi+1],2           ; set first allocated page as first
  2185.         or byte ptr [edi-3],4           ; set last allocated page as last
  2186.         clc                             ; carry clear, success
  2187.  
  2188. @@int310500vpmallocdone:
  2189.         mov eax,ebp                     ; EAX = number of pages allocated
  2190.     ret                ; return
  2191.  
  2192. ;-----------------------------------------------------------------------------
  2193. int310500vlmalloc:                      ; check for linear memory block
  2194.         mov edi,cs:pagetablebase        ; EDI = search ptr in page table
  2195.  
  2196.         mov ecx,cs:pagetabletop         ; ECX = count of pages to search
  2197.         sub ecx,edi
  2198.         shr ecx,2
  2199.  
  2200.         xor edx,edx                     ; EDX = largest linear block found
  2201.         xor eax,eax                     ; EAX = search unit, free entry (0)
  2202.  
  2203.         push ebx                        ; preserve EBX, memory requested
  2204.  
  2205. @@int310500vlmallocl0:
  2206.         jecxz short @@int310500vlmallocdone     ; if no more entries, done
  2207.  
  2208.         repne scas dword ptr es:[edi]   ; search for first next free entry
  2209.         jne short @@int310500vlmallocdone       ; if no more free, go on
  2210.  
  2211.         mov ebp,ecx                     ; EBP = current count
  2212.         lea ebx,[edi-4]                 ; EBX = start of free block
  2213.  
  2214.         repe scas dword ptr es:[edi]    ; search for end of free linear block
  2215.         jne short @@int310500vlmallocl0f0; if previous entry not free, go on
  2216.  
  2217.         inc ebp                         ; previous entry free, extra one
  2218.  
  2219. @@int310500vlmallocl0f0:
  2220.         sub ebp,ecx                     ; EBP = number of free pages in block
  2221.  
  2222.         cmp ebp,edx                     ; new block larger than last largest?
  2223.         jb @@int310500vlmallocl0        ; if no, loop
  2224.  
  2225.         mov esi,ebx                     ; ESI = ptr to largest block found
  2226.         mov edx,ebp                     ; size of new largest block found
  2227.  
  2228.         cmp ebp,[esp]                   ; block sufficient for memory request?
  2229.         jb @@int310500vlmallocl0        ; if no, loop
  2230.  
  2231. @@int310500vlmallocdone:
  2232.         pop ebx                         ; restore EBX, memory requested
  2233.         ret                             ; return
  2234.  
  2235. ;-----------------------------------------------------------------------------
  2236. int310500vmalloc:                       ; allocate linear+physical mem block
  2237.         call int310500vlmalloc          ; try to allocate linear memory block
  2238.  
  2239.         cmp edx,1                       ; found ANY free linear area?
  2240.         jc short @@int310500vmallocdone ; if no, done
  2241.  
  2242.         cmp edx,ebx                     ; linear block enough for request?
  2243.         jb short @@int310500vmallocf0   ; if no, go to physical memory check
  2244.  
  2245.         call int310500vpmalloc          ; try to allocate physical mem
  2246.  
  2247.         mov cl,1                        ; error is not enough physical memory
  2248.         jmp short @@int310500vmallocdone; go to done
  2249.  
  2250. @@int310500vmallocf0:
  2251.         mov ebx,edx                     ; only linear block size physical mem
  2252.  
  2253.         call int310500vpmalloc          ; try to allocate physical memory
  2254.         jc short @@int310500vmallocfaillinear   ; if failed, done
  2255.  
  2256.         call int310500vfree             ; success, so must free block
  2257.  
  2258.         mov eax,ebx                     ; can allocate this much total memory
  2259.         stc                             ; carry set, failed
  2260.  
  2261. @@int310500vmallocfaillinear:
  2262.         mov cl,0                        ; error is not enough linear memory
  2263.  
  2264. @@int310500vmallocdone:
  2265.         ret                             ; return
  2266.  
  2267. ;-----------------------------------------------------------------------------
  2268. int310500vfree:                         ; free linear+physical memory block
  2269.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2270.  
  2271. @@int310500vfreel0:
  2272.         xor ecx,ecx                     ; new page table entry is free (0)
  2273.     xchg ecx,[edi]            ; swap ECX with page table entry
  2274.     add edi,4            ; increment page table ptr
  2275.  
  2276.         mov edx,ecx                     ; EDX = page table entry
  2277.         and dx,0f000h                   ; mask off low 12 bits
  2278.  
  2279.         mov ax,0de05h                   ; VCPI free a page
  2280.         call fword ptr cs:vcpi_calleip
  2281.  
  2282.         test ch,4                       ; last page of block?
  2283.         jz @@int310500vfreel0           ; if no, loop
  2284.  
  2285.         ret                             ; return
  2286.  
  2287. ;─────────────────────────────────────────────────────────────────────────────
  2288. int310500v:                             ; VCPI get free memory information
  2289.         push ds                         ; ES = DS for VCPI malloc functions
  2290.         pop es
  2291.  
  2292.         mov ebx,0ffffffffh              ; try to allocate an impossible amount
  2293.         call int310500vmalloc
  2294.  
  2295.         shl eax,12                      ; returned EAX is highest possible
  2296.  
  2297.         jmp int310500xsetbuf            ; put memory information in buffer
  2298.  
  2299. ;─────────────────────────────────────────────────────────────────────────────
  2300. int310501v:                             ; VCPI allocate memory block
  2301.         push ds                         ; ES = DS for VCPI malloc functions
  2302.         pop es
  2303.  
  2304.         call int310500vbxcxtoebx        ; convert BX:CX bytes to EBX pages
  2305.  
  2306.         call int310500vmalloc           ; try to allocate requested amount
  2307.         jnc short int310501vaddxnhandle ; if successful, go to done
  2308.  
  2309.         or cl,cl                        ; error is not enough linear memory?
  2310.         jz int31fail8012                ; if yes, error 8013h
  2311.         jmp int31fail8013               ; error is physical, error 8013h
  2312.  
  2313. int310501vaddxnhandle:
  2314.         mov ecx,esi                     ; figure address of block from handle
  2315.         sub ecx,cs:pagetablebase
  2316.         shl ecx,10
  2317.         shld ebx,ecx,16
  2318.  
  2319.         mov di,si                       ; SI:DI = ESI, handle
  2320.         shr esi,16
  2321.  
  2322.         mov eax,cs:vcpi_cr3             ; reload CR3 to clear TLB
  2323.         mov cr3,eax
  2324.  
  2325.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2326.  
  2327. ;─────────────────────────────────────────────────────────────────────────────
  2328. int310502v:                             ; VCPI free memory block
  2329.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2330.  
  2331.         call int310500vfree             ; free memory block
  2332.  
  2333.         mov eax,cs:vcpi_cr3             ; reload CR3 to clear TLB
  2334.         mov cr3,eax
  2335.  
  2336.         jmp int31ok                     ; return ok
  2337.  
  2338. ;─────────────────────────────────────────────────────────────────────────────
  2339. int310503v:                             ; VCPI resize memory block
  2340.         push ds                         ; ES = DS for VCPI malloc functions
  2341.         pop es
  2342.  
  2343.         call int310500vbxcxtoebx        ; convert BX:CX bytes to EBX pages
  2344.  
  2345.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2346.  
  2347.         mov edi,esi                     ; EDI = ESI, ptr to linear block start
  2348.         xor ebp,ebp                     ; EBP = running block size in pages
  2349.  
  2350. @@int310503vl0:
  2351.         add edi,4                       ; increment page table ptr
  2352.         inc ebp                         ; increment block size
  2353.  
  2354.         test byte ptr [edi-3],4         ; last page of block?
  2355.         jz @@int310503vl0               ; if no, loop
  2356.  
  2357.         sub ebx,ebp                     ; EBX = change in block size
  2358.         jz int310501vaddxnhandle        ; if no change, done
  2359.  
  2360.         jc @@int310503vf0               ; if block made smaller, just free top
  2361.  
  2362.         mov ecx,cs:pagetabletop         ; ECX = count of pages to search
  2363.         sub ecx,edi
  2364.         shr ecx,2
  2365.  
  2366.         mov edx,ecx                     ; EDX = current count
  2367.         xor eax,eax                     ; EAX = search unit, free entry (0)
  2368.  
  2369.         jecxz short @@int310503vf3      ; if no entries above, try below
  2370.  
  2371.         repe scas dword ptr es:[edi]    ; check for free entries above block
  2372.         je short @@int310503vf2         ; if previous entry free, go on
  2373.  
  2374.         dec edx                         ; previous entry not free, minus one
  2375.  
  2376. @@int310503vf2:
  2377.         sub edx,ecx                     ; EDX = number of free pages in block
  2378.  
  2379.         cmp edx,ebx                     ; enough linear memory?
  2380.         jb short @@int310503vf3         ; if no, try below in linear memory
  2381.  
  2382.         push esi                        ; preserve start of block
  2383.         lea esi,[esi+ebp*4]             ; ESI -> start of new block for alloc
  2384.  
  2385.         call int310500vpmalloc          ; try to allocate physical memory
  2386.         mov edi,esi                     ; EDI -> start of new block
  2387.         pop esi                         ; restore start of old block
  2388.         jc int31fail8013                ; if alloc failed, error 8013h
  2389.  
  2390.         and byte ptr [edi-3],0fbh       ; clear last bit in old block end
  2391.         and byte ptr [edi+1],0fdh       ; clear first bit in new block start
  2392.  
  2393.         jmp int310501vaddxnhandle       ; go to done
  2394.  
  2395. @@int310503vf3:
  2396.         mov ecx,esi                     ; ECX = count of pages to search up
  2397.         sub ecx,cs:pagetablebase
  2398.         shr ecx,2
  2399.  
  2400.         or ecx,ecx                      ; any linear memory below?
  2401.         jz @@int310503vf1               ; if no, try to allocate
  2402.  
  2403.         push ebp                        ; preserve size of original block
  2404.  
  2405.         lea edi,[esi-4]                 ; EDI = ESI, ptr to linear block start
  2406.         mov ebp,ecx                     ; EBP = current count
  2407.  
  2408.         std                             ; search is up
  2409.         repe scas dword ptr es:[edi]    ; check for free entries after block
  2410.         cld
  2411.         je short @@int310503vf4         ; if previous entry free, go on
  2412.  
  2413.         dec ebp                         ; previous entry not free, minus one
  2414.  
  2415. @@int310503vf4:
  2416.         sub ebp,ecx                     ; EBP = number of free pages in block
  2417.         lea eax,[ebp+edx]               ; free size below + free size above
  2418.  
  2419.         pop ebp                         ; restore original block size
  2420.  
  2421.         cmp eax,ebx                     ; enough linear memory?
  2422.         jb @@int310503vf1               ; if no, try to allocate
  2423.  
  2424.         push esi                        ; preserve original block address
  2425.  
  2426.         sub ebx,edx                     ; EBX = number of pages needed below
  2427.         lea eax,[ebx*4]                 ; get base of block below
  2428.         sub esi,eax
  2429.  
  2430.         push edx ebp                    ; preserve some vars
  2431.         call int310500vpmalloc          ; try to allocate physical memory
  2432.         pop ebp edx                     ; restore some vars
  2433.  
  2434.         mov edi,esi                     ; EDI -> base of block below
  2435.         pop esi                         ; restore base of original block
  2436.         jc int31fail8013                ; if alloc failed, error 8013h
  2437.  
  2438.         or edx,edx                      ; any pages needed above?
  2439.         jz short @@int310503vf6         ; if no, go on
  2440.  
  2441.         push esi edi ebp                ; preserve some vars
  2442.  
  2443.         mov ebx,edx                     ; EBX = size of block below
  2444.         lea esi,[esi+ebp*4]             ; ESI -> start of block above
  2445.  
  2446.         call int310500vpmalloc          ; try to allocate physical memory
  2447.         pop ebp edi esi                 ; restore some vars
  2448.         jnc short @@int310503vf5        ; if allocated ok, go on
  2449.  
  2450.         mov esi,edi                     ; ESI -> allocated block below
  2451.         call int310500vfree             ; free allocated block below
  2452.  
  2453.         jmp int31fail8013               ; fail, error 8013h
  2454.  
  2455. @@int310503vf5:
  2456.         and byte ptr [esi-3],0fbh       ; clear last bit in below block end
  2457.         and byte ptr [esi+ebp*4+1],0fdh ; clear first bit in above block start
  2458.  
  2459. @@int310503vf6:
  2460.         and byte ptr [edi+1],0fdh       ; clear first bit in below block start
  2461.         and byte ptr [esi+ebp*4-3],0fbh ; clear last bit in old block end
  2462.  
  2463.         push edi                        ; preserve new block start
  2464.  
  2465.         mov edx,edi                     ; EDX = base of move area
  2466.         lea ebx,[esi-4]                 ; EBX = current location in move area
  2467.  
  2468. @@int310503vl1:
  2469.         mov edi,ebx                     ; set up to shift up a page
  2470.         mov esi,ebx
  2471.         mov ecx,ebp
  2472.  
  2473.         lods dword ptr ds:[esi]         ; shift old pages a page down in table
  2474.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  2475.         stos dword ptr es:[edi]
  2476.  
  2477.         sub ebx,4                       ; decrement to next page to shift
  2478.         cmp ebx,edx                     ; more pages to shift?
  2479.         jae @@int310503vl1              ; if yes, loop
  2480.  
  2481.         pop esi                         ; restore new block start address
  2482.  
  2483.         jmp int310501vaddxnhandle       ; go to done
  2484.  
  2485. @@int310503vf1:
  2486.         add ebx,ebp                     ; restore EBX as requested size
  2487.  
  2488.         push esi ebp                    ; preserve some vars
  2489.         call int310500vlmalloc          ; check for linear memory block
  2490.         pop ebp edi                     ; restore some vars
  2491.  
  2492.         cmp edx,ebx                     ; enough linear memory?
  2493.         jb int31fail8012                ; if no, error 8012h
  2494.  
  2495.         sub ebx,ebp                     ; EBX = extra pages needed
  2496.         push esi                        ; preserve for later copy
  2497.         lea esi,[esi+ebp*4]             ; ESI -> start of extra space needed
  2498.  
  2499.         push edi ebp                    ; preserve some vars
  2500.         call int310500vpmalloc          ; try to allocate physical memory
  2501.         pop ecx esi edi                 ; restore some vars
  2502.         jc int31fail8013                ; if not enough mem, error 8013h
  2503.  
  2504.         push edi esi ecx                ; preserve, new and old block, size
  2505.  
  2506.         rep movs dword ptr es:[edi],dword ptr ds:[esi]  ; copy old block pages
  2507.  
  2508.         and byte ptr [edi-3],0fbh       ; clear last bit in old block end
  2509.         and byte ptr [edi+1],0fdh       ; clear first bit in new block start
  2510.  
  2511.         pop ecx edi                     ; restore to clear old block
  2512.  
  2513.         xor eax,eax                     ; new page table entry is free (0)
  2514.         rep stos dword ptr es:[edi]     ; clear old page table block
  2515.  
  2516.         pop esi                         ; restore new block address
  2517.  
  2518.         jmp int310501vaddxnhandle       ; go to done
  2519.  
  2520. @@int310503vf0:
  2521.         sub edi,4                       ; decrement page table ptr
  2522.  
  2523.         xor edx,edx                     ; new page table entry is free (0)
  2524.         xchg edx,[edi]                  ; swap EDX with page table entry
  2525.         and dx,0f000h                   ; mask off low 12 bits
  2526.  
  2527.         mov ax,0de05h                   ; VCPI free a page
  2528.         call fword ptr cs:vcpi_calleip
  2529.  
  2530.         inc ebx                         ; increment negative change counter
  2531.         jnz @@int310503vf0              ; if more pages to free, loop
  2532.  
  2533.         or byte ptr [edi-3],4           ; set next page up as last of block
  2534.  
  2535.         jmp int310501vaddxnhandle       ; go to done
  2536.  
  2537. ;─────────────────────────────────────────────────────────────────────────────
  2538. int31050av:                             ; VCPI get memory block size and base
  2539.         shrd ecx,esi,16                 ; figure address of block from handle
  2540.         mov cx,di
  2541.         sub ecx,cs:pagetablebase
  2542.         shl ecx,10
  2543.         shld ebx,ecx,16
  2544.  
  2545.         call int310500vsiditoesi        ; convert handle SI:DI to ptr ESI
  2546.  
  2547.         xor edi,edi                     ; EDI = running page count
  2548.  
  2549. @@int31050avl0:
  2550.         inc edi                         ; increment page count
  2551.  
  2552.         lods dword ptr ds:[esi]         ; EAX = page table entry
  2553.         test ah,4                       ; is this the last page of the block?
  2554.         jz @@int31050avl0               ; if no, loop
  2555.  
  2556.         shl edi,12                      ; convert EDI pages to bytes
  2557.         shld esi,edi,16                 ; SI:DI = EDI, size in bytes
  2558.  
  2559.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2560.  
  2561. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2562. ; XMS EXTENDED MEMORY FUNCTIONS
  2563. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2564.  
  2565. ;-----------------------------------------------------------------------------
  2566. int310500xsetbuf:
  2567.         mov es,[esp+24h]                ; get ES:EDI buffer ptr from stack
  2568.         mov edi,[esp]
  2569.  
  2570.         stos dword ptr es:[edi]         ; store block size in output buffer
  2571.         mov ecx,0bh                     ; fill rest of buffer with 0ffffffffh
  2572.         mov eax,0ffffffffh
  2573.         rep stos dword ptr es:[edi]
  2574.  
  2575.         jmp int31ok                     ; return ok
  2576.  
  2577. ;-----------------------------------------------------------------------------
  2578. int310500xcallxms:                      ; make a all to real mode XMS driver
  2579.         pop bp                          ; pop return address
  2580.         sub esp,32h                     ; stack space for register structure
  2581.  
  2582.         mov [esp+1ch],ax                ; put AX in register structure
  2583.         mov [esp+10h],bx                ; put BX in register structure
  2584.         mov [esp+18h],cx                ; put CX in register structure
  2585.         mov [esp+14h],dx                ; put DX in register structure
  2586.  
  2587.         mov word ptr [esp+20h],0        ; zero FLAGS in register structure
  2588.         mov dword ptr [esp+2eh],0       ; zero SS:SP in register structure
  2589.         mov eax,dword ptr cs:xms_callip ; put XMS driver address in CS:IP in
  2590.         mov [esp+2ah],eax               ;  regis]er structure
  2591.  
  2592.         push ss                         ; ES:EDI -> register structure
  2593.         pop es
  2594.         mov edi,esp
  2595.  
  2596.         xor cx,cx                       ; copy 0 words as stack parameters
  2597.         xor bh,bh                       ; doesnt really need to be here
  2598.         mov ax,301h                     ; call real mode FAR procedure
  2599.         int 31h
  2600.  
  2601.         mov ax,[esp+1ch]                ; get AX from register structure
  2602.         mov bx,[esp+10h]                ; get BX from register structure
  2603.         mov cx,[esp+18h]                ; get CX from register structure
  2604.         mov dx,[esp+14h]                ; get DX from register structure
  2605.  
  2606.         lea esp,[esp+32h]               ; adjust ESP without changing FLAGS
  2607.         jc int31fail8010                ; if INT 31h failed, error 8010h
  2608.  
  2609.         jmp bp                          ; return ok
  2610.  
  2611. ;-----------------------------------------------------------------------------
  2612. int310500xbxcxtodx:                     ; convert BX:CX bytes to DX K
  2613.         pop bp                          ; pop return address
  2614.  
  2615.         mov dx,cx                       ; check for invalid value, BX=CX=0
  2616.         or dx,bx
  2617.         jz int31fail8021                ; if invalid value, error 8021h
  2618.  
  2619.         add cx,1023+15                  ; adjust for size in K and align
  2620.         adc bx,0
  2621.  
  2622.         test bh,0fch                    ; memory request too high
  2623.         jnz int31fail8013               ; if yes, error 8013h
  2624.  
  2625.         shrd cx,bx,10                   ; CX = memory in K
  2626.         mov dx,cx
  2627.  
  2628.         jmp bp                          ; return ok
  2629.  
  2630. ;-----------------------------------------------------------------------------
  2631. int310500xerror:                        ; XMS error, return with DPMI error
  2632.         cmp bl,0a0h                     ; out of memory?
  2633.         je int31fail8013                ; if yes, error 8013h
  2634.  
  2635.         cmp bl,0a1h                     ; handles exhausted?
  2636.         je int31fail8016                ; if yes, error 8016h
  2637.  
  2638.         cmp bl,0a2h                     ; invalid handle?
  2639.         je int31fail8023                ; if yes, error 8023h
  2640.  
  2641.         jmp int31fail8010               ; else, error 8010h
  2642.  
  2643. ;─────────────────────────────────────────────────────────────────────────────
  2644. int310500x:                             ; XMS get free memory information
  2645.         mov ah,8                        ; get largest free memory block in K
  2646.         call int310500xcallxms
  2647.  
  2648.         movzx eax,ax                    ; EAX = free memory in bytes
  2649.         shl eax,10
  2650.  
  2651.         sub eax,15                      ; adjust by extra alignment size
  2652.         jnc int310500xsetbuf            ; if no overflow, put info to buffer
  2653.  
  2654.         xor eax,eax                     ; overflow, so no memory available
  2655.         jmp int310500xsetbuf            ; put memory information in buffer
  2656.  
  2657. ;─────────────────────────────────────────────────────────────────────────────
  2658. int310501x:                             ; XMS allocate memory block
  2659.         call int310500xbxcxtodx         ; convert BX:CX bytes to DX K
  2660.         mov cx,dx                       ; preserve size of block in K
  2661.  
  2662.         mov ah,9                        ; allocate DX K of XMS memory
  2663.         call int310500xcallxms
  2664.         or ax,ax                        ; error?
  2665.         jz int310500xerror              ; if yes, convert XMS error to DPMI
  2666.  
  2667.         mov si,dx                       ; get DPMI handle from XMS handle
  2668.  
  2669. int310501xgotmem:
  2670.         mov ah,0ch                      ; lock memory block
  2671.         call int310500xcallxms
  2672.         or ax,ax                        ; error?
  2673.         jnz short @@int310501xf0        ; if no, go on
  2674.  
  2675.         push bx                         ; yup, preserve error number
  2676.  
  2677.         mov ah,0ah                      ; free block causing lock error
  2678.         call int310500xcallxms
  2679.  
  2680.         pop bx                          ; restore error number
  2681.         jmp int310500xerror             ; XMS error, return with DPMI error
  2682.  
  2683. @@int310501xf0:
  2684.         mov di,cx                       ; low word of DPMI handle is size in K
  2685.  
  2686.         mov cx,bx                       ; XMS linear address to DPMI regs
  2687.         mov bx,dx
  2688.  
  2689.         add cx,0fh                      ; align linear address on paragraph
  2690.         adc bx,0
  2691.         and cl,0f0h
  2692.  
  2693.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2694.  
  2695. ;─────────────────────────────────────────────────────────────────────────────
  2696. int310502x:                             ; XMS free memory block
  2697.         mov dx,si                       ; get XMS handle from DPMI handle
  2698.  
  2699.         mov ah,0dh                      ; unlock memory block
  2700.         call int310500xcallxms
  2701.         or ax,ax                        ; error?
  2702.         jz int310500xerror              ; if XMS error, return with DPMI error
  2703.  
  2704.         mov ah,0ah                      ; free memory block
  2705.         call int310500xcallxms
  2706.         or ax,ax                        ; error?
  2707.         jz int310500xerror              ; if yes, convert XMS error to DPMI
  2708.  
  2709.         jmp int31ok                     ; return ok
  2710.  
  2711. ;─────────────────────────────────────────────────────────────────────────────
  2712. int310503x:                             ; XMS resize memory block
  2713.         call int310500xbxcxtodx         ; convert BX:CX bytes to DX K
  2714.         mov cx,dx                       ; preserve size of block in K
  2715.         mov dx,si                       ; get XMS handle from DPMI handle
  2716.  
  2717.         mov ah,0dh                      ; unlock memory block
  2718.         call int310500xcallxms
  2719.         or ax,ax                        ; error?
  2720.         jz int310500xerror              ; if XMS error, return with DPMI error
  2721.  
  2722.         mov bx,cx                       ; BX = new size in K
  2723.         mov ah,0fh                      ; resize memory block
  2724.         call int310500xcallxms
  2725.         mov dx,si                       ; get XMS handle again
  2726.         or ax,ax                        ; error in resize?
  2727.         jnz int310501xgotmem            ; if no, go to memory block code
  2728.  
  2729.         push bx                         ; yup, preserve error number
  2730.  
  2731.         mov ah,0ch                      ; lock memory block
  2732.         call int310500xcallxms
  2733.  
  2734.         pop bx                          ; restore error number
  2735.         jmp int310500xerror             ; XMS error, return with DPMI error
  2736.  
  2737. ;─────────────────────────────────────────────────────────────────────────────
  2738. int31050ax:                             ; XMS get memory block size and base
  2739.         mov dx,si                       ; get XMS handle from DPMI handle
  2740.         mov si,di                       ; SI = size of block in K
  2741.  
  2742.         mov ah,0dh                      ; unlock memory block
  2743.         call int310500xcallxms
  2744.         or ax,ax                        ; error?
  2745.         jz int310500xerror              ; if XMS error, return with DPMI error
  2746.  
  2747.         mov ah,0ch                      ; lock memory block
  2748.         call int310500xcallxms
  2749.         or ax,ax                        ; error?
  2750.         jz int310500xerror              ; if XMS error, return with DPMI error
  2751.  
  2752.         xor di,di                       ; convert size in K to size in bytes
  2753.         shrd di,si,6
  2754.         shr si,6
  2755.  
  2756.         mov cx,bx                       ; XMS linear address to DPMI regs
  2757.         mov bx,dx
  2758.  
  2759.         mov ax,cx                       ; figure out alignment stub
  2760.         dec ax
  2761.         and ax,0fh
  2762.         xor al,0fh
  2763.  
  2764.         sub di,ax                       ; subtract alignment stub from size
  2765.         sbb si,0
  2766.  
  2767.         add cx,0fh                      ; align linear address on paragraph
  2768.         adc bx,0
  2769.         and cl,0f0h
  2770.  
  2771.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2772.  
  2773. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2774. ; RAW EXTENDED MEMORY FUNCTIONS
  2775. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2776.  
  2777. ;-----------------------------------------------------------------------------
  2778. int310500rnomem:                        ; no free extended memory present
  2779.         xor eax,eax                     ; 0 available extended memory
  2780.         jmp int310500xsetbuf            ; put memory information in buffer
  2781.  
  2782. ;-----------------------------------------------------------------------------
  2783. int310500rbxcxtoebx:                    ; convert BX:CX bytes to EBX bytes
  2784.         pop bp                          ; pop return address
  2785.  
  2786.         shl ebx,16                      ; EBX = BX:CX
  2787.         mov bx,cx
  2788.  
  2789.         or ebx,ebx                      ; check for invalid value
  2790.         jz int31fail8021                ; if invalid value, error 8021h
  2791.  
  2792.         add ebx,0fh                     ; align EBX on paragraph
  2793.         and bl,0f0h
  2794.  
  2795.         jmp bp                          ; return ok
  2796.  
  2797. ;-----------------------------------------------------------------------------
  2798. int310500rfindmcb:                      ; find MCB for handle SI:DI
  2799.         pop bp                          ; pop return address
  2800.  
  2801.         shl esi,16                      ; ESI = handle SI:DI = address of MCB
  2802.         mov si,di
  2803.  
  2804.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2805.  
  2806. @@int310500rfindmcbl0:
  2807.         cmp edi,esi                     ; found MCB?
  2808.         jne short @@int310500rfindmcbl0f0       ; if no, keep looking
  2809.  
  2810.         cmp byte ptr [edi-4],0          ; memory block free?
  2811.         je int31fail8023                ; if yes, error 8023h
  2812.  
  2813.         jmp bp                          ; return ok, found MCB
  2814.  
  2815. @@int310500rfindmcbl0f0:
  2816.         mov edi,[edi-12]                ; EDI -> next memory control block
  2817.         or edi,edi                      ; is there another MCB?
  2818.         jnz @@int310500rfindmcbl0       ; if yes, loop
  2819.  
  2820.         jmp int31fail8023               ; fail, error 8023h
  2821.  
  2822. ;-----------------------------------------------------------------------------
  2823. int310500radjustused:                   ; adjust INT 15h extended memory used
  2824.         mov eax,cs:rawextmemtop         ; EAX -> first memory control block
  2825.  
  2826. @@int310500radjustusedl0:
  2827.         cmp dword ptr [eax-12],0        ; last memory control block?
  2828.         jz short @@int310500radjustusedf0       ; if yes, go to set new used K
  2829.  
  2830.         mov eax,[eax-12]                ; EAX -> next memory control block
  2831.         jmp @@int310500radjustusedl0    ; loop
  2832.  
  2833. @@int310500radjustusedf0:
  2834.         cmp byte ptr [eax-4],0          ; memory block free?
  2835.         je short @@int310500radjustusedf1       ; if no, go on
  2836.  
  2837.         sub eax,[eax-16]                ; used, adjust by size of block
  2838.  
  2839. @@int310500radjustusedf1:
  2840.         sub eax,10h                     ; adjust by size of MCB
  2841.         and eax,0fffffc00h              ; align on K
  2842.         sub eax,cs:rawextmemtop         ; size of extended memory used
  2843.         neg eax
  2844.         shr eax,10                      ; convert from bytes to K
  2845.  
  2846.         mov ebp,cs:codebase             ; EBP = offset of PMODE_TEXT from 0
  2847.         mov ds:rawextmemused[ebp],ax    ; adjust INT 15h extended memory used
  2848.  
  2849. @@int310500radjustuseddone:
  2850.         ret                             ; return
  2851.  
  2852. ;-----------------------------------------------------------------------------
  2853. int310500rlinkmcb:                      ; link memory blocks at ESI and EDI
  2854.         mov eax,[esi-16]                ; combine two block sizes
  2855.         add eax,10h
  2856.         add [edi-16],eax                ; add size of next block to this one
  2857.         mov ecx,[esi-12]                ; copy next MCB field
  2858.         mov [edi-12],ecx
  2859.         jecxz short @@int310500rlinkmcbf0       ; if no next MCB, done
  2860.  
  2861.         mov [ecx-8],edi                 ; set prev MCB in next MCB to this MCB
  2862.  
  2863. @@int310500rlinkmcbf0:
  2864.         ret                             ; return
  2865.  
  2866. ;─────────────────────────────────────────────────────────────────────────────
  2867. int310500r:                             ; raw get free memory information
  2868.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2869.  
  2870.         xor eax,eax                     ; running highest free memory block
  2871. @@int310500rl0:
  2872.         cmp byte ptr [edi-4],0          ; is block free?
  2873.         jne short @@int310500rl0f0      ; if no, loop
  2874.  
  2875.         mov ebx,[edi-16]                ; EBX = size of block
  2876.         cmp eax,ebx                     ; last free block larger?
  2877.         ja short @@int310500rl0f0       ; if yes, loop
  2878.  
  2879.         mov eax,ebx                     ; found larger block, new largest
  2880.  
  2881. @@int310500rl0f0:
  2882.         mov edi,[edi-12]                ; EDI -> next memory control block
  2883.         or edi,edi                      ; is there another MCB?
  2884.         jnz @@int310500rl0              ; if yes, loop
  2885.  
  2886.         jmp int310500xsetbuf            ; put memory information in buffer
  2887.  
  2888. ;─────────────────────────────────────────────────────────────────────────────
  2889. int310501r:                             ; raw allocate memory block
  2890.         call int310500rbxcxtoebx        ; convert BX:CX bytes to EBX bytes
  2891.  
  2892.         mov edi,cs:rawextmemtop         ; EDI -> first memory control block
  2893.  
  2894. @@int310501rl0:
  2895.         cmp byte ptr ds:[edi-4],0       ; is block free?
  2896.         je short @@int310501rl0f2       ; if yes, check block
  2897.  
  2898. @@int310501rl0f0:
  2899.         mov edi,[edi-12]                ; EDI -> next memory control block
  2900.         or edi,edi                      ; is there another MCB?
  2901.         jnz @@int310501rl0              ; if yes, loop
  2902.  
  2903.         jmp int31fail8013               ; fail, error 8013h
  2904.  
  2905. @@int310501rl0f2:
  2906.         lea ecx,[edi-10h]               ; ECX -> possible new MCB
  2907.         sub ecx,ebx
  2908.  
  2909.         mov eax,[edi-16]                ; EAX = size of block
  2910.         sub eax,ebx                     ; enough free memory in block?
  2911.         jc short @@int310501rl0f0       ; if no, loop
  2912.  
  2913.         jz short @@int310501rl0f1       ; if exactly same size, continue
  2914.  
  2915.         sub eax,10h                     ; adjust for size of new created MCB
  2916.         mov [ecx-16],eax                ; put size of new block in new MCB
  2917.         mov eax,ecx                     ; set next MCB in old MCB as new one
  2918.         xchg [edi-12],eax               ; copy next MCB from old to new MCB
  2919.         mov [ecx-12],eax
  2920.         or eax,eax                      ; is there a next MCB?
  2921.         jz short @@int310501rl0f3       ; if no, go on
  2922.  
  2923.         mov [eax-8],ecx                 ; set prev MCB in next MCB to new MCB
  2924.  
  2925. @@int310501rl0f3:
  2926.         mov [ecx-8],edi                 ; set prev MCB in new MCB as old one
  2927.         mov byte ptr [ecx-4],0          ; set new MCB as free
  2928.         mov [edi-16],ebx                ; set size of allocated block
  2929.  
  2930. @@int310501rl0f1:
  2931.         mov byte ptr [edi-4],1          ; set block as allocated
  2932.  
  2933. int310501raddxnhandle:
  2934.         shld ebx,ecx,16                 ; BX:CX = ECX, address of block
  2935.         shld esi,edi,16                 ; SI:DI = EDI, handle (address of MCB)
  2936.  
  2937.         call int310500radjustused       ; adjust INT 15h extended memory used
  2938.  
  2939.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  2940.  
  2941. ;─────────────────────────────────────────────────────────────────────────────
  2942. int310502r:                             ; raw free memory block
  2943.         call int310500rfindmcb          ; find MCB for handle SI:DI
  2944.  
  2945.         mov byte ptr [edi-4],0          ; set this memory block as free
  2946.  
  2947.         mov esi,[edi-12]                ; ESI -> next memory control block
  2948.         or esi,esi                      ; is there next MCB?
  2949.         jz short @@int310502rf0         ; if no, go on
  2950.  
  2951.         cmp byte ptr [esi-4],0          ; is next memory block free?
  2952.         jne short @@int310502rf0        ; if no, go on
  2953.  
  2954.         call int310500rlinkmcb          ; link two memory blocks
  2955.  
  2956. @@int310502rf0:
  2957.         mov esi,[edi-8]                 ; ESI -> previous memory control block
  2958.         or esi,esi                      ; is there previous MCB?
  2959.         jz short @@int310502rf1         ; if no, go on
  2960.  
  2961.         cmp byte ptr [esi-4],0          ; is previous memory block free?
  2962.         jne short @@int310502rf1        ; if no, go on
  2963.  
  2964.         xchg esi,edi                    ; change mcb order for function
  2965.         call int310500rlinkmcb          ; link two memory blocks
  2966.  
  2967. @@int310502rf1:
  2968.         call int310500radjustused       ; adjust INT 15h extended memory used
  2969.  
  2970.         jmp int31ok                     ; return ok
  2971.  
  2972. ;─────────────────────────────────────────────────────────────────────────────
  2973. int310503r:                             ; raw resize memory block
  2974.         call int310500rbxcxtoebx        ; convert BX:CX bytes to EBX bytes
  2975.         mov edx,ebx                     ; EDX = size of new block
  2976.  
  2977.         call int310500rfindmcb          ; find MCB for handle SI:DI
  2978.  
  2979.         push ds                         ; ES = DS for possible block copy
  2980.         pop es
  2981.  
  2982.         sub ebx,[esi-16]                ; EBX = change in block size
  2983.         jz @@int310503rf0               ; if no change, done
  2984.  
  2985.         jc @@int310503rf1               ; if block made smaller, just free top
  2986.  
  2987.         xor eax,eax                     ; running memory counter
  2988.  
  2989.         mov ecx,[esi-12]                ; ECX -> next MCB
  2990.         jecxz short @@int310503rf4      ; if no next MCB, check previous MCB
  2991.  
  2992.         cmp byte ptr [ecx-4],0          ; next MCB free?
  2993.         jne short @@int310503rf4        ; if not, check previous MCB
  2994.  
  2995.         mov eax,[ecx-16]                ; EAX = amount of free memory in block
  2996.         add eax,10h                     ;  including memory control block
  2997.  
  2998. @@int310503rf4:
  2999.         mov ecx,[esi-8]                 ; ECX -> previous MCB
  3000.         jecxz short @@int310503rf5      ; if no previous MCB, check memory
  3001.  
  3002.         cmp byte ptr [ecx-4],0          ; previous MCB free?
  3003.         jne short @@int310503rf5        ; if not, check memory
  3004.  
  3005.         add eax,[ecx-16]                ; add amount of free memory in block
  3006.         add eax,10h                     ;  including memory control block
  3007.  
  3008. @@int310503rf5:
  3009.         cmp eax,ebx                     ; enough to resize within area
  3010.         jb @@int310503rf3               ; if no, try to allocate
  3011.  
  3012.         or ecx,ecx                      ; is there a previous MCB?
  3013.         jz @@int310503rf6               ; if no, resize to next
  3014.  
  3015.         cmp byte ptr [ecx-4],0          ; previous MCB free?
  3016.         jne short @@int310503rf6        ; if not, resize to next
  3017.  
  3018.         mov ebp,[ecx-16]                ; EBP = size of previous block, try to
  3019.         add ebp,10h                     ;  resize within previous block
  3020.  
  3021.         sub ebp,ebx                     ; EBP = prev block size - needed size
  3022.         jbe short @@int310503rf7        ; if prev block too small, go on
  3023.  
  3024.         mov edi,ecx                     ; EDI -> new MCB for new memory block
  3025.         sub edi,ebp                     ;  resize will fit entirely
  3026.  
  3027.         lea eax,[ebp-10h]               ; EAX = new size of free block
  3028.         mov [ecx-16],eax                ; store mew free size in prev MCB
  3029.         mov [edi-16],edx                ; store new size in new MCB
  3030.         mov [ecx-12],edi                ; set next MCB in prev MCB to new MCB
  3031.         mov [edi-8],ecx                 ; set prev MCB in new MCB to prev MCB
  3032.         mov byte ptr [edi-4],1          ; set new MCB as used
  3033.  
  3034.         mov ecx,[esi-12]                ; copy next MCB field
  3035.         mov [edi-12],ecx
  3036.         or ecx,ecx                      ; is there a next MCB
  3037.         jz @@int310503rf0               ; if no, go to block readjust
  3038.  
  3039.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3040.  
  3041.         jmp @@int310503rf0              ; go to block readjust
  3042.  
  3043. @@int310503rf7:
  3044.         mov edi,ecx                     ; EDI -> new MCB for new memory block
  3045.  
  3046.         lea eax,[edx+ebp]               ; EAX = size of new block
  3047.         mov [edi-16],eax                ; store mew free size in new MCB
  3048.         mov byte ptr [edi-4],1          ; set new MCB as used
  3049.  
  3050.         mov ecx,[esi-12]                ; copy next MCB field
  3051.         mov [edi-12],ecx
  3052.         jecxz short @@int310503rf8      ; if no next MCB, go on
  3053.  
  3054.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3055.  
  3056. @@int310503rf8:
  3057.         add ebp,ebx                     ; EBP = size of block just acquired
  3058.         sub ebx,ebp                     ; EBX = new size still needed
  3059.         jz @@int310503rf0               ; if no more space needed, done
  3060.  
  3061.         mov esi,edi                     ; ESI -> new MCB
  3062.  
  3063. @@int310503rf6:
  3064.         mov edi,[esi-12]                ; EDI -> next MCB
  3065.  
  3066.         mov ecx,[edi-12]                ; copy next MCB field
  3067.         mov [esi-12],ecx
  3068.         jecxz short @@int310503rf9      ; if no next MCB, go on
  3069.  
  3070.         mov [ecx-8],esi                 ; set prev MCB in next MCB to this MCB
  3071.  
  3072. @@int310503rf9:
  3073.         mov eax,[edi-16]                ; EAX = size of next memory block
  3074.         add eax,10h
  3075.  
  3076.         sub edi,eax                     ; EDI -> start of next memory block
  3077.         sub eax,ebx                     ; EAX = amount of free space left
  3078.  
  3079.         mov ecx,[esi-16]                ; ECX = old size of this memory block
  3080.         mov [esi-16],edx                ; store new size in this MCB
  3081.         mov byte ptr [esi-4],1          ; set this MCB as used
  3082.  
  3083.         sub esi,ecx                     ; ESI -> start of this memory block
  3084.         sub esi,10h
  3085.  
  3086.         shr ecx,2                       ; copy this memory block down in mem
  3087.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  3088.  
  3089.         add esi,10h                     ; adjust ESI to top MCB
  3090.         mov edi,esi                     ; EDI -> top MCB
  3091.  
  3092.         mov ebx,eax                     ; EBX = negative of space free at top
  3093.         neg ebx
  3094.         jz @@int310503rf0               ; in no space free, go to done
  3095.  
  3096.         jmp short @@int310503rf1        ; set new MCBs for moved block
  3097.  
  3098. @@int310503rf3:
  3099.         mov ebp,edi                     ; preserve old block MCB address
  3100.         sub edx,ebx                     ; EDX = size of old block
  3101.  
  3102.         mov bx,[esp+16]                 ; BX:CX = new block size from stack
  3103.         mov cx,[esp+24]
  3104.         mov ax,501h                     ; try to allocate new block
  3105.         int 31h
  3106.         jc int31failax                  ; if could not, fail with error AX
  3107.  
  3108.         shrd eax,esi,16                 ; EAX -> new block MCB
  3109.         mov ax,di
  3110.  
  3111.         shrd edi,ebx,16                 ; EDI -> start of new block
  3112.         mov di,cx
  3113.  
  3114.         lea esi,[ebp-10h]               ; ESI -> start of old block
  3115.         sub esi,edx
  3116.  
  3117.         mov ecx,edx                     ; copy memory from old block to new
  3118.         shr ecx,2
  3119.         rep movs dword ptr es:[edi],dword ptr ds:[esi]
  3120.  
  3121.         mov edx,eax                     ; EDX -> new block MCB
  3122.  
  3123.         shld esi,ebp,16                 ; SI:DI = handle of old block
  3124.         mov di,bp
  3125.         mov ax,0502h                    ; free old block
  3126.         int 31h
  3127.  
  3128.         mov edi,edx                     ; EDI -> new block MCB for done
  3129.  
  3130.         jmp short @@int310503rf0        ; go to done
  3131.  
  3132. @@int310503rf1:
  3133.         lea edi,[esi+ebx]               ; EDI -> new MCB for new memory block
  3134.  
  3135.         lea eax,[ebx+10h]               ; EAX = size of freed block
  3136.         neg eax
  3137.         mov [esi-16],eax                ; store freed size in old MCB
  3138.         mov [edi-16],edx                ; store new size in new MCB
  3139.  
  3140.         mov ecx,[esi-12]                ; copy next MCB field
  3141.         mov [edi-12],ecx
  3142.         jecxz short @@int310503rf2      ; if no next MCB, go on
  3143.  
  3144.         mov [ecx-8],edi                 ; set prev MCB in next MCB to new MCB
  3145.  
  3146. @@int310503rf2:
  3147.         mov [esi-12],edi                ; set next MCB in old MCB as new MCB
  3148.         mov [edi-8],esi                 ; set prev MCB in new MCB as old MCB
  3149.         mov byte ptr [edi-4],1          ; set new MCB as used
  3150.         mov byte ptr [esi-4],0          ; set old MCB as free
  3151.  
  3152.         mov ecx,[esi-8]                 ; ECX -> prev MCB of old MCB
  3153.         jecxz short @@int310503rf0      ; if no prev MCB, done
  3154.  
  3155.         cmp byte ptr [ecx-4],0          ; is previous MCB free?
  3156.         jne short @@int310503rf0        ; if no, dont link
  3157.  
  3158.         push edi                        ; preserve new MCB
  3159.         mov edi,ecx                     ; top MCB = prev MCB for link function
  3160.         call int310500rlinkmcb          ; link two memory blocks
  3161.         pop edi                         ; restore new MCB
  3162.  
  3163. @@int310503rf0:
  3164.         mov ecx,[edi-16]                ; ECX = base address of new block
  3165.         neg ecx
  3166.         lea ecx,[ecx+edi-10h]
  3167.         
  3168.         jmp int310501raddxnhandle       ; return address and handle
  3169.  
  3170. ;─────────────────────────────────────────────────────────────────────────────
  3171. int31050ar:                             ; raw get memory block size and base
  3172.         call int310500rfindmcb          ; find MCB for handle SI:DI
  3173.  
  3174.         mov edi,[esi-16]                ; EDI = size of memory block
  3175.         lea ecx,[esi-10h]               ; get base address of memory block
  3176.         sub ecx,edi
  3177.  
  3178.         shld ebx,ecx,16                 ; BX:CX = ECX, address of block
  3179.         shld esi,edi,16                 ; SI:DI = EDI, size of memory block
  3180.  
  3181.         jmp int31oksinoax               ; return ok, with SI, DI, BX, CX
  3182.  
  3183. PMODE_TEXT      ends
  3184. end
  3185.  
  3186.